﻿#include "dryctrlthread.h"
#include "rtdb.h"
#include  <math.h>

#define SIGNAL_LOG_COUNT 60

//#define EMS_CTRL_SWITCH_CLOSE_STR    "IO控制汇流开关合闸."
//#define EMS_CTRL_SWITCH_OPEN_STR     "IO控制汇流开关分闸."
//#define SERIAL_IO_DEV_CONN_ERROR	"串口继电器通信故障."
//#define SERIAL_IO_DEV_CONN_OK		"串口继电器通信恢复."

//#define SWITCH_CLOSED_STR    		"汇流开关合闸."
//#define SWITCH_OPENED_STR     	"汇流开关分闸."

//unsigned char  g_DIState = 0;// 4路继电器输出4路开关量输入（转发卡） 的DI状态 DI1和DI2闭合时值为3， 只有DI3闭合时值为4
//unsigned char  g_DOState = 0;// 4路继电器输出4路开关量输入（转发卡） 的DO状态 DO1和DO2闭合时值为3， 只有DO3闭合时值为4
//int      g_bReadDiFlag = 0; // 是否已经获取到DI状态
//int      g_bReadDoFlag = 0; // 是否已经获取到DO状态
//quint16  g_connFailedCount = 0; // 通迅故障计时，通迅正常时清0

int g_testCount = 0;

// added 2024-10-28
QString getDOName(QList<int> list)
{
    QString strName;
    for (int i = 0; i < list.size(); ++i)
    {
        int doIndex = list.at(i);
        if (i > 0)
            strName += ",";
        strName += QString("DO%1").arg(doIndex + 1);
    }

    return strName;
}

void limitAlmCount(quint16 &devAlarmCount)
{
    if (devAlarmCount > 10000)  //防止次数太大溢出
    {
        devAlarmCount = 10000;
    }
}

/*
3.8.0、2.0.0项目通用
aEnvTemp[30]水浸告警使能aEnvTemp[31]水浸告警
aEnvTemp[32]消防告警使能aEnvTemp[33]消防告警
aEnvTemp[34]消防启动使能aEnvTemp[35]消防启动
aEnvTemp[36]消防故障使能aEnvTemp[37]消防故障
*/
char old485Alarm[10] = {0,0,0,0,0,0,0,0,0,0};
char g_runCount = 1;
int g_masterHZCmd = 0; // added 204-4-26
char has485WaterAlarm(int type) // added 2024-1-6
{
    QString strContextCn = "";
    QString strContextEn = "";
    char ret = 0;
    if (0 == KgGlobalData::ms_enabled485Alarm)
        return 0;
#ifdef VER20_EMS
    if (1 == type)
    {
        ret = 1;
    }
    else
    {
        if (1)
        {
            char tmpVal = 0;//KgGlobalData::ms_pStack->aEnvTemp[31];
            if ((KgGlobalData::ms_pStack->aEnvWaterAlarm[0]&2) > 0)
                tmpVal = 1;
            ret = tmpVal;
            if (g_runCount > 0)
            {
                if (0 == old485Alarm[0] && tmpVal > 0)
                {
                    saveLogToBaDb("发生水浸告警(协议通迅).", "water alarm starting(protocol comm)");
                }
                if (old485Alarm[0] > 0 && 0 == tmpVal)
                {
                    saveLogToBaDb("水浸告警结束(协议通迅).", "water alarm finished(protocol comm)");
                }
            }
            old485Alarm[0] = tmpVal;
        }
    }

#else
    if (1 == type)
    {
        if (1 == KgGlobalData::ms_pStack->aEnvTemp[30])
            ret = 1;
    }
    else
    {
        if (1 == KgGlobalData::ms_pStack->aEnvTemp[30])
        {
            char tmpVal = KgGlobalData::ms_pStack->aEnvTemp[31];
            ret = tmpVal;
            if (g_runCount > 0)
            {
                if (0 == old485Alarm[0] && tmpVal > 0)
                {
                    strContextCn = "发生水浸告警(协议通迅).";
                    strContextEn = "Water leakage alarm occurred (protocol communication).";
                    saveLogToBaDb(strContextCn, strContextEn);

                }
                if (old485Alarm[0] > 0 && 0 == tmpVal)
                {
                    strContextCn = "水浸告警结束(协议通迅).";
                    strContextEn = "Water leakage alarm finished(protocol communication).";
                    saveLogToBaDb(strContextCn, strContextEn);
                }
            }
            old485Alarm[0] = tmpVal;
        }
    }
#endif
    return ret;
}

char has485XfWarm(int type) // added 2024-1-6
{
    QString strContextCn = "";
    QString strContextEn = "";
    char ret = 0;
    if (0 == KgGlobalData::ms_enabled485Alarm)
        return 0;
#ifdef VER20_EMS // added 2024-10-27
    if (1 == type)
    {
        ret = 1;
    }
    else
    {
        if (1)
        {
            CXfData *pXfData = KgGlobalData::ms_pRTDB->getXfDev(0);
            char tmpVal = 0;// KgGlobalData::ms_pStack->aEnvTemp[33];
            if (1 == pXfData->usDevTemp[1])
                tmpVal = 1;
            ret = tmpVal;
            if (g_runCount > 0)
            {
                if (0 == old485Alarm[1] && tmpVal > 0)
                {
                    saveLogToBaDb(kgConvert("发生消防告警(协议通迅)."));// 485
                }
                if (old485Alarm[1] > 0 && 0 == tmpVal)
                {
                    saveLogToBaDb(kgConvert("消防告警结束(协议通迅)."));
                }
            }
            old485Alarm[1] = tmpVal;
        }
    }
#else
    if (1 == type)
    {
        if (1 == KgGlobalData::ms_pStack->aEnvTemp[32])
            ret = 1;
    }
    else
    {
        if (1 == KgGlobalData::ms_pStack->aEnvTemp[32])
        {
            char tmpVal = KgGlobalData::ms_pStack->aEnvTemp[33];
            ret = tmpVal;
            if (g_runCount > 0)
            {
                if (0 == old485Alarm[1] && tmpVal > 0)
                {
                    strContextCn = "发生消防告警(协议通迅).";
                    strContextEn = "fire alarm starting(protocol communication).";
                    saveLogToBaDb(strContextCn, strContextEn);
                }
                if (old485Alarm[1] > 0 && 0 == tmpVal)
                {
                    strContextCn = "消防告警结束(协议通迅).";
                    strContextEn = "fire alarm finished(protocol communication).";
                    saveLogToBaDb(strContextCn, strContextEn);
                }
            }
            old485Alarm[1] = tmpVal;
        }
    }

#endif
    return ret;
}

char has485XfMotion(int type)
{
    QString strContextCn = "";
    QString strContextEn = "";
    char ret = 0;
    if (0 == KgGlobalData::ms_enabled485Alarm)
        return 0;
#ifdef VER20_EMS // added 2024-10-27
    if (1 == type)
    {
        ret = 1;
    }
    else
    {
        if (1)
        {
            CXfData *pXfData = KgGlobalData::ms_pRTDB->getXfDev(0);
            char tmpVal = 0;//KgGlobalData::ms_pStack->aEnvTemp[35];
            if (1 == pXfData->usDevTemp[0] || pXfData->usDevTemp[1] > 1)
                tmpVal = 1;
            ret = tmpVal;
            if (g_runCount > 0)
            {
                if (0 == old485Alarm[2] && tmpVal > 0)
                {
                    saveLogToBaDb(kgConvert("发生消防启动(协议通迅)."));
                }
                if (old485Alarm[2] > 0 && 0 == tmpVal)
                {
                    saveLogToBaDb(kgConvert("消防启动结束(协议通迅)."));
                }
            }
            old485Alarm[2] = tmpVal;
        }
    }
#else
    if (1 == type)
    {
        if (1 == KgGlobalData::ms_pStack->aEnvTemp[34])
            ret = 1;
    }
    else
    {
        if (1 == KgGlobalData::ms_pStack->aEnvTemp[34])
        {
            char tmpVal = KgGlobalData::ms_pStack->aEnvTemp[35];
            ret = tmpVal;
            if (g_runCount > 0)
            {
                if (0 == old485Alarm[2] && tmpVal > 0)
                {
                    strContextCn = "发生消防启动(协议通迅).";
                    strContextEn = "fire action starting(protocol communication).";
                    saveLogToBaDb(strContextCn, strContextEn);
                }
                if (old485Alarm[2] > 0 && 0 == tmpVal)
                {
                    strContextCn = "消防启动结束(协议通迅).";
                    strContextEn = "fire action finished(protocol communication).";
                    saveLogToBaDb(strContextCn, strContextEn);
                }
            }
            old485Alarm[2] = tmpVal;
        }
    }
#endif
    return ret;
}

char has485XfFault(int type)
{
    QString strContextCn = "";
    QString strContextEn = "";
    char ret = 0;
    if (0 == KgGlobalData::ms_enabled485Alarm)
        return 0;
#ifdef VER20_EMS // added 2024-10-27
    if (1 == type)
    {
        ret = 1;
    }
    else
    {
        if (1)
        {
            CXfData *pXfData = KgGlobalData::ms_pRTDB->getXfDev(0);
            char tmpVal = 0;//KgGlobalData::ms_pStack->aEnvTemp[37];
            if (2 == pXfData->usDevTemp[0])
                tmpVal = 1;
            ret = tmpVal;
            if (g_runCount > 0)
            {
                if (0 == old485Alarm[3] && tmpVal > 0)
                {
                    saveLogToBaDb(kgConvert("发生消防故障(协议通迅)."));//484
                }
                if (old485Alarm[3] > 0 && 0 == tmpVal)
                {
                    saveLogToBaDb(kgConvert("消防故障结束(协议通迅)."));
                }
            }
            old485Alarm[3] = tmpVal;
        }
    }

#else
    if (1 == type)
    {
        if (1 == KgGlobalData::ms_pStack->aEnvTemp[36])
            ret = 1;
    }
    else
    {
        if (1 == KgGlobalData::ms_pStack->aEnvTemp[36])
        {
            char tmpVal = KgGlobalData::ms_pStack->aEnvTemp[37];
            ret = tmpVal;
            if (g_runCount > 0)
            {
                if (0 == old485Alarm[3] && tmpVal > 0)
                {
                    strContextCn = "发生消防故障(协议通迅).";
                    strContextEn = "fire fault starting(protocol communication).";
                    saveLogToBaDb(strContextCn, strContextEn);
                }
                if (old485Alarm[3] > 0 && 0 == tmpVal)
                {
                    strContextCn = "消防故障结束(协议通迅).";
                    strContextEn = "fire fault finished(protocol communication).";
                    saveLogToBaDb(strContextCn, strContextEn);
                }
            }
            old485Alarm[3] = tmpVal;
        }
    }
#endif
    return ret;
}

void DryCtrlThread::sendLog(int iLogType, const QString& strLog)
{
    writeKgLogfile(strLog);
}

DryCtrlThread::DryCtrlThread(QObject *parent)
    : QThread(parent)
{
    m_pIOReader = new IOReader(this, KgGlobalData::ms_comDevName);
    m_pStack = 0;
    m_fireAlarmCount = 0;
    m_fireAlarm = 0;
    m_fireAlarm = 0;
    // m_fireDetectAlarm = 0;
    m_oldFireAlarm = 0;
    m_fireSignal = 0;

    m_fireSprayCount = 0;
    m_fireSpraySignal = 0;
    m_fireSprayAlarm = 0;
    m_oldFireSprayAlarm = 0;

    m_fireFaultCount = 0;
    m_fireFaultAlarm = 0;

    m_waterCount = 0;
    m_waterAlarm = 0;
    m_waterSignal = 0;

    m_thunderCount = 0;
    m_thunderAlarm = 0;
    m_thunderSignal = 0;

    m_emergStopCount = 0;
    m_emergStopAlarm = 0;
    m_usOldEmerStopState = 0;
    m_emergStopSignal = 0;

    m_waterCountSec = 0;
    m_waterAlarmSec = 0;
    m_waterSignalSec = 0;

    m_thunderCountSec = 0;
    m_thunderAlarmSec = 0;
    m_thunderSignalSec = 0;

    m_emergStopCountSec = 0;
    m_emergStopAlarmSec = 0;
    m_emergStopSignalSec = 0;

    m_bmsLocalCount = 0;
    m_bmsLocalSignal = 0;
    m_bmsLocalState = 0;  // 1:BMS就地 0:BMS远方

    m_bmsRemoteCount = 0;
    m_bmsRemoteSignal = 0;
    m_bmsRemoteState = 0;  // 1:BMS远方 0:S就地

    m_combusGasCount = 0;
    m_combusGasAlarm = 0;
    m_combusGasDetectAlarm = 0;
    m_combusGasSignal = 0;

    m_fuseCount = 0;
    m_fuseAlarm = 0;
    m_fuseSignal = 0;

    m_xfMotionCount = 0;
    m_xfMotionAlarm = 0;

    m_fireManuCount = 0;
    m_fireManuMode = 0;

    m_elecPowerOffCount = 0;
    m_elecPowerOffAlarm = 0;

    m_xfWarmCount= 0;
    m_xfWarmMsg= 0;

    m_upsAlarmCount = 0;
    m_upsAlarm= 0;

    m_doorAlarmCount = 0;
    m_doorAlarm= 0;

    m_doorAlarmCountSec = 0;
    m_doorAlarmSec = 0;

    m_acFaultCount = 0;
    m_acFault = 0;

    m_lqFaultCount = 0;
    m_lqFault = 0;

    m_stackState = 0;                // 当前堆状态
    m_statChangeTime = QDateTime();  // 堆状态改变时间

    //m_hlkgState = 99;
    for (int i = 0; i < MAX_HLKG_COUNT; ++i)
    {
        m_hlkgState[i] = 99;
    }

    for (int i = 0; i < MAX_GLKG_COUNT; ++i)
    {
        m_glkgState[i] = 99;
    }

    for (int i = 0; i < 10; ++i)
    {
        m_bankFaultTimeCount[i] = 0;
    }


    m_drvFzCount = 0;   // 已发送分闸/脱扣命令记数
    m_drvFzSuccedCount = 0;
    //drvFzTime;      // 最近一次驱动分闸时间

    m_drvHzCount = 0;   // 已发送合闸命令记数
    m_drvHzSuccedCount = 0;

    m_oldConnState = 0; // 并网连接状态

    m_masterFzCount = 0;// 主动分闸记数
    m_masterHzCount = 0;// 主动合闸记数

    m_saveEmsCtrlHzRdCount = 0;// 保存EMS控制汇流开关记录后计时
    m_saveEmsCtrlFzRdCount = 0;
    m_saveRejectEmsHzRdCount = 0;

    m_detectYcCount = 0;
    m_detectOkCount = 0;

    //m_setDoCount = 0;

    m_usOldHasAlarm = 0;
    m_usOldHasProt = 0;

    m_usConnFailed = 99; // 是否有通迅故障 0:无 1:有, 99:没有初始化

    m_usOldChgJcqState = 99;
    m_usOldDchgJcqState = 99;

    //m_iLogCount = 0;

    m_xfTkMotionCount = 0;
    m_xfTkMotionLogCount = 0;
    m_emgTkMotionLogCount = 0;

    m_xfSprayTkMotionCount = 0;
    m_xfSprayTkMotionLogCount = 0;

    m_volDownProtTkCount = 0;
    m_volDownProtTkLogCount = 0;

    m_signalLogCount = 0;

    m_isolSwitchClosedCount = 0;
    m_isolSwitchOpendCount = 0;

    m_xfAlarmLog = 0;
    m_xfXfMotionLog = 0;
    m_xfXfErrorLog = 0;

    m_hasReadIoState = 0;
    for (int i = 0; i < 16; ++i)
    {
        m_usOldDI[i] = 0;
    }

    for (int i = 0; i < MAX_BANK_NUM; ++i)
    {
        m_oldBankState[i] = 0;
    }

    for (int i = 0; i < 10; ++i)
    {
        m_reservedAlarm[i] = 0;
        m_reservedCount[i] = 0;
    }

    m_oldCtrlFanState = 0;
    m_closeFanReqCount = 0;

    m_mainSwitchCount = 0;
    m_mainSwitchClosed = 0;

    this->netDebug = new QNetDebug();
    netDebug->init("192.168.1.74", 7777);  // Server IP and port
    netDebug->setApplicationName("MyApplication");
}
// 检测16个DI状态并在状态变化时更新到xnbmsio.ini文件
bool DryCtrlThread::updateDIValuesToIniFile(CBattStack *pStack)
{
    static int lastDIValues[16] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; // 记录上次的DI状态值
    bool hasStateChanged = false;
    quint16  DIBits= KgGlobalData::ms_dryData.DIVal;    //Bit0: DI1  Bit1: DI2  以此类推
    // 获取第一个电池组的DI值作为参考

    // 从DIBits中提取DI5-DI16的状态值
    for (int i = 4; i < 16; i++)
    {
        // 检查DIBits中对应位是否为1
        diValues[i] = (DIBits & (1 << i)) ? 1 : 0;
    }

    // 检查DI1-DI4是否有变化，并更新到pStack
    if (lastDIValues[0] != diValues[0] || lastDIValues[0] == -1)
    {
        pStack->usDI1 = diValues[0];
        hasStateChanged = true;
    }

    if (lastDIValues[1] != diValues[1] || lastDIValues[1] == -1)
    {
        pStack->usDI2 = diValues[1];
        hasStateChanged = true;
    }

    if (lastDIValues[2] != diValues[2] || lastDIValues[2] == -1)
    {
        pStack->usDI3 = diValues[2];
        hasStateChanged = true;
    }

    if (lastDIValues[3] != diValues[3] || lastDIValues[3] == -1)
    {
        pStack->usDI4 = diValues[3];
        hasStateChanged = true;
    }

    // 检查DI5-DI16是否有变化，并更新到ini文件
    QSettings settings("../ini/xnbmsio.ini", QSettings::IniFormat);

    for (int i = 4; i < 16; i++)
    {
        if (lastDIValues[i] != diValues[i] || lastDIValues[i] == -1)
        {
            // 更新ini文件中的DI值
            settings.setValue(QString("DI_VALUE/DI%1").arg(i+1), diValues[i]);
            hasStateChanged = true;

            // 记录状态变化日志
            if (lastDIValues[i] != -1) // 不是首次检测
            {
                QString strLog = QString("DI%1 state changed from %2 to %3")
                .arg(i+1)
                    .arg(lastDIValues[i])
                    .arg(diValues[i]);
                netDebug->kgWrite(strLog);
            }
        }
    }
    //netDebug->kgWrite("123");
    // 更新lastDIValues数组
    for (int i = 0; i < 16; i++)
    {
        lastDIValues[i] = diValues[i];
    }

    return hasStateChanged;
}

DryCtrlThread::~DryCtrlThread()
{

}

// 判断对应的干结点是否发生告警 added 2021-2-22
// bool HasAlarmVal(XFStrategy stg, unsigned char dIState, int type, QString &strPos) // modifed 2023-3-13
bool HasAlarmVal(XFStrategy stg, int dIState, int type, QString &strPos)
{
    bool bAlarm = false;
    for (int i = 0; i < stg.diList.size(); ++i)
    {
        DI_STU diStu = stg.diList[i];
        int xfMask = 1 << diStu.diIndex;
        //printf("dIState==========%d\n", dIState);
        if (1 == diStu.alarmValue) // 常开干结点
        {
            if (xfMask == (xfMask & dIState))// 有告警
            {
                bAlarm = true;
                if (strPos.length() > 0)
                {
                    strPos +=",";
                }
                strPos += QString("%1").arg(0+diStu.diIndex);
            }
            else
            {
                ;
            }
        }
        else  // 常闭干结点
        {
            if (xfMask == (xfMask & dIState))
            {

            }
            else // 有告警
            {
                bAlarm = true;
                if (strPos.length() > 0)
                {
                    strPos +=",";
                }
                strPos += QString("%1").arg(0+diStu.diIndex);
            }
        }
    }

    return bAlarm;
}

void DryCtrlThread::judgeXfAlarm()
{
    QString strContextCn = "";
    QString strContextEn = "";
    // sendLog(0, "==============judgeXfAlarm() step1");
    if (KgGlobalData::ms_xfStrategy.diList.size() > 0 || has485XfWarm(1)) // 有采集消防信号
    {
        QString strPos;
        if (HasAlarmVal(KgGlobalData::ms_xfStrategy, KgGlobalData::ms_dryData.DIVal,1,strPos))
        {
            if (++m_fireAlarmCount >= KgGlobalData::ms_xfStrategy.confirmedCount)
            {
                if (0 == m_fireAlarm)
                {
                    strContextCn = KgGlobalData::ms_xfStrategy.diName + QString("(DI%1).").arg(strPos);
                    strContextEn = KgGlobalData::ms_xfStrategy.diName_EN + QString("(DI%1).").arg(strPos);
                    saveLogToBaDb(strContextCn, strContextEn);
                }
                m_fireAlarm  = 1;
                //sendLog(0, "==============judgeXfAlarm()  step2");
                sendLog(0, QString("******************fireAlarm(DI%1)").arg(strPos));
            }

            limitAlmCount(m_fireAlarmCount);
        }
        else
        {
            //sendLog(0, "==============judgeXfAlarm()  step3");
            if (1 == m_fireAlarm)
            {
                strContextCn = KgGlobalData::ms_xfStrategy.diOverName;
                strContextEn = KgGlobalData::ms_xfStrategy.diOverName_EN;
                saveLogToBaDb(strContextCn, strContextEn);
            }

            m_fireAlarmCount = 0;
            m_fireAlarm = 0;
            //m_fireDetectAlarm = 0;
            m_fireSignal = 0;
            //sendLog(0, "fireAlarm is 0");
        }

        //KgGlobalData::ms_pStack->aEnvFireAction = m_fireAlarm;
        //KgGlobalData::ms_pStack->aFireWarn = m_fireAlarm; // 消防告警 modified 2023-3-13
        char xfAlarm485 = has485XfWarm(2);
#ifdef VER20_EMS // added 2024-4-28
        /*CXfData *pXfData = KgGlobalData::ms_pRTDB->getXfDev(0);
		if (pXfData)
		{
			if (xfAlarm485 > 0) // 消防报警
			    pXfData->fireAlarm = xfAlarm485;
			else if (1 == m_fireAlarm)
				pXfData->fireAlarm = 1;
			else
				pXfData->fireAlarm = 0;
		}*/
#endif
        if (xfAlarm485 > 0 || 1 == m_fireAlarm)
        {
            KgGlobalData::ms_pStack->aFireWarn = 1;
        }
        else
        {
            KgGlobalData::ms_pStack->aFireWarn = 0;
        }
    }
    // sendLog(0, "==============judgeXfAlarm()  step4");
}

void DryCtrlThread::judgeXfSparyAlam() // added 2022-12-10
{
    QString strContextCn = "";
    QString strContextEn = "";
    if (KgGlobalData::ms_xfSprayStrategy.diList.size() > 0 || has485XfMotion(1)) // 有采集消防喷洒信号
    {
        QString strPos;
        if (HasAlarmVal(KgGlobalData::ms_xfSprayStrategy, KgGlobalData::ms_dryData.DIVal,1,strPos))
        {
            if (++m_fireSprayCount >= KgGlobalData::ms_xfSprayStrategy.confirmedCount)
            {
                if (0 == m_fireSprayAlarm)
                {
                    strContextCn = KgGlobalData::ms_xfSprayStrategy.diName + QString("(DI%1).").arg(strPos);
                    strContextEn = KgGlobalData::ms_xfSprayStrategy.diName_EN + QString("(DI%1).").arg(strPos);
                    saveLogToBaDb(strContextCn, strContextEn);
                }
                m_fireSprayAlarm  = 1;
                sendLog(0, QString("******************fireSprayAlarm(DI%1)").arg(strPos));
            }

            limitAlmCount(m_fireSprayCount);
        }
        else
        {
            if (1 == m_fireSprayAlarm)
            {
                strContextCn = KgGlobalData::ms_xfSprayStrategy.diOverName;
                strContextEn = KgGlobalData::ms_xfSprayStrategy.diOverName_EN;
                saveLogToBaDb(strContextCn, strContextEn);
            }

            m_fireSprayCount = 0;
            m_fireSprayAlarm = 0;
            m_fireSpraySignal = 0;
        }

        //KgGlobalData::ms_pStack->aFireAction = m_fireSprayAlarm; // modified 2023-3-13
        char xfSpray485 = has485XfMotion(2);
#ifdef VER20_EMS // added 2024-4-28
        /*CXfData *pXfData = KgGlobalData::ms_pRTDB->getXfDev(0);
		if (pXfData)
		{
		    if (xfSpray485 > 0) // 消防启动
			    pXfData->spryAlarm = xfSpray485;
			else if (1 == m_fireSprayAlarm)
				pXfData->spryAlarm = 1;
			else
				pXfData->spryAlarm = 0;
		}*/
#endif
        if (xfSpray485 > 0 || 1 == m_fireSprayAlarm)
        {
            KgGlobalData::ms_pStack->aFireAction = 1;
        }
        else
        {
            KgGlobalData::ms_pStack->aFireAction = 0;
        }
    }
}

void DryCtrlThread::judgeXfFaultAlam() // added 2022-12-21
{
    QString strContextCn = "";
    QString strContextEn = "";
    if (KgGlobalData::ms_xfFaultStrategy.diList.size() > 0 || has485XfFault(1)) // 有采集消防故障信号
    {
        QString strPos;
        if (HasAlarmVal(KgGlobalData::ms_xfFaultStrategy, KgGlobalData::ms_dryData.DIVal,1,strPos))
        {
            if (++m_fireFaultCount >= KgGlobalData::ms_xfFaultStrategy.confirmedCount)
            {
                if (0 == m_fireFaultAlarm)
                {
                    strContextCn = KgGlobalData::ms_xfFaultStrategy.diName + QString("(DI%1).").arg(strPos);
                    strContextEn = KgGlobalData::ms_xfFaultStrategy.diName_EN + QString("(DI%1).").arg(strPos);
                    saveLogToBaDb(strContextCn, strContextEn);
                }
                m_fireFaultAlarm  = 1;
                sendLog(0, QString("******************fireFaultAlarm(DI%1)").arg(strPos));
            }

            limitAlmCount(m_fireFaultCount);
        }
        else
        {
            if (1 == m_fireFaultAlarm)
            {
                strContextCn = KgGlobalData::ms_xfFaultStrategy.diOverName;
                strContextEn = KgGlobalData::ms_xfFaultStrategy.diOverName_EN;
                saveLogToBaDb(strContextCn, strContextEn);
            }

            m_fireFaultCount = 0;
            m_fireFaultAlarm = 0;
        }

        //KgGlobalData::ms_pStack->aEnvFireFault = m_fireFaultAlarm;
        //KgGlobalData::ms_pStack->aFireFault = m_fireFaultAlarm;        // 消防故障
        char xfFault485 = has485XfFault(2);
#ifdef VER20_EMS // added 2024-4-28
        /*CXfData *pXfData = KgGlobalData::ms_pRTDB->getXfDev(0);
		if (pXfData)
		{
			if (xfFault485 > 0) // 消防设备故障
			    pXfData->devError = xfFault485;
			else if (1 == m_fireFaultAlarm)
				pXfData->devError = 1;
			else
				pXfData->devError = 0;
		}*/
#endif
        if (xfFault485 > 0 || 1 == m_fireFaultAlarm)
        {
            KgGlobalData::ms_pStack->aFireFault = 1;
        }
        else
        {
            KgGlobalData::ms_pStack->aFireFault = 0;
        }
    }
}

void DryCtrlThread::judgeXfAutoManu()  //  27
{
    QString strContextCn = "";
    QString strContextEn = "";
    if (KgGlobalData::ms_xfManuAutoStrategy.diList.size() > 0)
    {
        QString strPos;
        if (HasAlarmVal(KgGlobalData::ms_xfManuAutoStrategy, KgGlobalData::ms_dryData.DIVal,1,strPos))
        {
            if (++m_fireManuCount >= KgGlobalData::ms_xfManuAutoStrategy.confirmedCount)
            {
                if (0 == m_fireManuMode)
                {
                    strContextCn = KgGlobalData::ms_xfManuAutoStrategy.diName + QString("(DI%1).").arg(strPos);
                    strContextEn = KgGlobalData::ms_xfManuAutoStrategy.diName_EN + QString("(DI%1).").arg(strPos);
                    saveLogToBaDb(strContextCn, strContextEn);
                }
                m_fireManuMode  = 1;
                sendLog(0, QString("******************Xf ManuMode(DI%1)").arg(strPos));
            }

            limitAlmCount(m_fireManuCount);
        }
        else
        {
            if (1 == m_fireManuMode)
            {
                strContextCn = KgGlobalData::ms_xfManuAutoStrategy.diOverName;
                strContextEn = KgGlobalData::ms_xfManuAutoStrategy.diOverName_EN;
                saveLogToBaDb(strContextCn, strContextEn);
            }

            m_fireManuCount = 0;
            m_fireManuMode = 0;
        }

        //KgGlobalData::ms_pStack->aEnvFireFault = m_fireFaultAlarm;
        //KgGlobalData::ms_pStack->aFireFault = m_fireFaultAlarm;                        // 消防故障
        KgGlobalData::ms_pStack->aEnvTemp[15] = m_fireManuMode;
    }
}

void DryCtrlThread::judgeElecPowerOff()  //  27
{
    QString strContextCn = "";
    QString strContextEn = "";
    if (KgGlobalData::ms_elecPowerOffStrategy.diList.size() > 0)
    {
        QString strPos;
        if (HasAlarmVal(KgGlobalData::ms_elecPowerOffStrategy, KgGlobalData::ms_dryData.DIVal,1,strPos))
        {
            if (++m_elecPowerOffCount >= KgGlobalData::ms_elecPowerOffStrategy.confirmedCount)
            {
                if (0 == m_elecPowerOffAlarm)
                {
                    strContextCn = KgGlobalData::ms_elecPowerOffStrategy.diName + QString("(DI%1).").arg(strPos);
                    strContextEn = KgGlobalData::ms_elecPowerOffStrategy.diName_EN + QString("(DI%1).").arg(strPos);
                    saveLogToBaDb(strContextCn, strContextEn);
                }
                m_elecPowerOffAlarm  = 1;
                sendLog(0, QString("******************Elec power off(DI%1)").arg(strPos));
            }

            limitAlmCount(m_elecPowerOffCount);
        }
        else
        {
            if (1 == m_elecPowerOffAlarm)
            {
                strContextCn = KgGlobalData::ms_elecPowerOffStrategy.diOverName;
                strContextEn = KgGlobalData::ms_elecPowerOffStrategy.diOverName_EN;
                saveLogToBaDb(strContextCn, strContextEn);
            }

            m_elecPowerOffCount = 0;
            m_elecPowerOffAlarm = 0;
        }

        //KgGlobalData::ms_pStack->aEnvFireFault = m_fireFaultAlarm;
        //KgGlobalData::ms_pStack->aFireFault = m_fireFaultAlarm;                        // 消防故障
        KgGlobalData::ms_pStack->aEnvTemp[18] = m_elecPowerOffAlarm;
    }
}

void DryCtrlThread::judgeWaterAlarm()
{
    QString strContextCn = "";
    QString strContextEn = "";


    if (KgGlobalData::ms_waterStrategy.diList.size() > 0) // 有采集水浸信号
    {
        QString strPos;
        if (HasAlarmVal(KgGlobalData::ms_waterStrategy, KgGlobalData::ms_dryData.DIVal,1,strPos))
        {
            if (++m_waterCount >= KgGlobalData::ms_waterStrategy.confirmedCount)
            {
                if (0 == m_waterAlarm)
                {
                    strContextCn = KgGlobalData::ms_waterStrategy.diName + QString("(DI%1).").arg(strPos);
                    strContextEn = KgGlobalData::ms_waterStrategy.diName_EN + QString("(DI%1).").arg(strPos);
                    saveLogToBaDb(strContextCn, strContextEn);
                }
                m_waterAlarm  = 1;
                sendLog(0, QString("******************waterAlarm(DI%1)").arg(strPos));
            }

            limitAlmCount(m_waterCount);
        }
        else
        {
            if (1 == m_waterAlarm)
            {
                strContextCn = KgGlobalData::ms_waterStrategy.diOverName;
                strContextEn = KgGlobalData::ms_waterStrategy.diOverName_EN;
                saveLogToBaDb(strContextCn, strContextEn);
            }
            m_waterCount = 0;
            m_waterAlarm = 0;
            m_waterSignal = 0;
            //sendLog(0, "waterAlarm is 0");
        }
        KgGlobalData::ms_pStack->aEnvWaterAlarm[0] = m_waterAlarm;
        //KgGlobalData::ms_pStack->aWaterAlarm = m_waterAlarm;                       // 水浸告警
    }
}

void DryCtrlThread::judgeWaterAlarmSec()
{
    QString strContextCn = "";
    QString strContextEn = "";
    if (KgGlobalData::ms_waterStrategySec.diList.size() > 0) // 有采集水浸信号
    {
        QString strPos;
        if (HasAlarmVal(KgGlobalData::ms_waterStrategySec, KgGlobalData::ms_dryData.DIVal,1,strPos))
        {
            if (++m_waterCountSec >= KgGlobalData::ms_waterStrategySec.confirmedCount)
            {
                if (0 == m_waterAlarmSec)
                {
                    strContextCn = KgGlobalData::ms_waterStrategySec.diName + QString("(DI%1).").arg(strPos);
                    strContextEn = KgGlobalData::ms_waterStrategySec.diName_EN + QString("(DI%1).").arg(strPos);
                    saveLogToBaDb(strContextCn, strContextEn);
                }
                m_waterAlarmSec  = 1;
                sendLog(0, QString("******************2# WaterAlarm(DI%1)").arg(strPos));
            }

            limitAlmCount(m_waterCountSec);
        }
        else
        {
            if (1 == m_waterAlarmSec)
            {
                strContextCn = KgGlobalData::ms_waterStrategySec.diOverName;
                strContextEn = KgGlobalData::ms_waterStrategySec.diOverName_EN;
                saveLogToBaDb(strContextCn, strContextEn);
            }
            m_waterCountSec = 0;
            m_waterAlarmSec = 0;
            m_waterSignalSec = 0;
            //sendLog(0, "waterAlarm is 0");
        }
        KgGlobalData::ms_pStack->aEnvWaterAlarm[1] = m_waterAlarmSec;
        //KgGlobalData::ms_pStack->aWaterAlarm = m_waterAlarm;    // 水浸告警
    }
}

void DryCtrlThread::judgeThunderAlarm()
{
    QString strContextCn = "";
    QString strContextEn = "";
    if (KgGlobalData::ms_tdStrategy.diList.size() > 0)  // 有采集防雷信号
    {
        QString strPos;
        if (HasAlarmVal(KgGlobalData::ms_tdStrategy, KgGlobalData::ms_dryData.DIVal,2,strPos))
        {
            if (++m_thunderCount >= KgGlobalData::ms_tdStrategy.confirmedCount)
            {
                if (0 == m_thunderAlarm)
                {
                    strContextCn = KgGlobalData::ms_tdStrategy.diName + QString("(DI%1).").arg(strPos);
                    strContextEn = KgGlobalData::ms_tdStrategy.diName_EN + QString("(DI%1).").arg(strPos);
                    saveLogToBaDb(strContextCn, strContextEn);
                }
                m_thunderAlarm  = 1;
                sendLog(0, QString("******************ThunderAlarm(DI%1)").arg(strPos));
            }

            limitAlmCount(m_thunderCount);
        }
        else
        {
            if (1 == m_thunderAlarm)
            {
                strContextCn = KgGlobalData::ms_tdStrategy.diOverName;
                strContextEn = KgGlobalData::ms_tdStrategy.diOverName_EN;
                saveLogToBaDb(strContextCn, strContextEn);
            }
            m_thunderCount = 0;
            m_thunderAlarm = 0;
            m_thunderSignal = 0;
            //sendLog(0, "thunderAlarm is 0");
        }
        //KgGlobalData::ms_pStack->aStackTemp[5] = m_thunderAlarm;
        KgGlobalData::ms_pStack->aEnvTemp[12] = m_thunderAlarm;
    }
}

void DryCtrlThread::judgeThunderAlarmSec()
{
    QString strContextCn = "";
    QString strContextEn = "";
    if (KgGlobalData::ms_tdStrategySec.diList.size() > 0)  // 有采集防雷信号
    {
        QString strPos;
        if (HasAlarmVal(KgGlobalData::ms_tdStrategySec, KgGlobalData::ms_dryData.DIVal,2,strPos))
        {
            if (++m_thunderCountSec >= KgGlobalData::ms_tdStrategySec.confirmedCount)
            {
                if (0 == m_thunderAlarmSec)
                {
                    strContextCn = KgGlobalData::ms_tdStrategySec.diName + QString("(DI%1).").arg(strPos);
                    strContextEn = KgGlobalData::ms_tdStrategySec.diName_EN + QString("(DI%1).").arg(strPos);
                    saveLogToBaDb(strContextCn, strContextEn);
                }
                m_thunderAlarmSec  = 1;
                sendLog(0, QString("******************2# ThunderAlarm(DI%1)").arg(strPos));
            }

            limitAlmCount(m_thunderCountSec);
        }
        else
        {
            if (1 == m_thunderAlarmSec)
            {
                strContextCn = KgGlobalData::ms_tdStrategySec.diOverName;
                strContextEn = KgGlobalData::ms_tdStrategySec.diOverName_EN;
                saveLogToBaDb(strContextCn, strContextEn);
            }
            m_thunderCountSec = 0;
            m_thunderAlarmSec = 0;
            m_thunderSignalSec = 0;
            //sendLog(0, "thunderAlarm is 0");
        }
        //KgGlobalData::ms_pStack->aStackTemp[5] = m_thunderAlarm;
        KgGlobalData::ms_pStack->aEnvTemp[13] = m_thunderAlarmSec;
    }
}

void DryCtrlThread::judgeEmergeStop()
{
    QString strContextCn = "";
    QString strContextEn = "";
    if (KgGlobalData::ms_emgStopStrategy.diList.size() > 0) // 有采集急停信号
    {
        QString strPos;
        if (HasAlarmVal(KgGlobalData::ms_emgStopStrategy, KgGlobalData::ms_dryData.DIVal,3,strPos))
        {
            if (++m_emergStopCount  >= KgGlobalData::ms_emgStopStrategy.confirmedCount)
            {
                if (0 == m_emergStopAlarm)
                {
                    strContextCn = KgGlobalData::ms_emgStopStrategy.diName + QString("(DI%1).").arg(strPos);
                    strContextEn = KgGlobalData::ms_emgStopStrategy.diName_EN + QString("(DI%1).").arg(strPos);
                    saveLogToBaDb(strContextCn, strContextEn);
                }
                m_emergStopAlarm  = 1;
                sendLog(0, QString("******************EmergStopAlarm(DI%1)").arg(strPos));
            }

            limitAlmCount(m_emergStopCount);
        }
        else
        {
            if (1 == m_emergStopAlarm)
            {
                strContextCn = KgGlobalData::ms_emgStopStrategy.diOverName;
                strContextEn = KgGlobalData::ms_emgStopStrategy.diOverName_EN;
                saveLogToBaDb(strContextCn, strContextEn);
            }
            m_emergStopCount = 0;
            m_emergStopAlarm = 0;
            m_emergStopSignal = 0;
            //sendLog(0, "emergStopAlarm is 0");
        }

        if (m_emergStopAlarm) // 发生急停
        {
            //KgGlobalData::ms_pStack->usEmerStopState = 1;
            ///KgGlobalData::ms_pStack->aEmerStop = 1;
            //writeKgLogfile(QString("step3 EmerStopState pStack->usEmerStopState=%1").arg(KgGlobalData::ms_pStack->usEmerStopState));
        }
        else       // 正常
        {
            //KgGlobalData::ms_pStack->usEmerStopState = 2;
            ///KgGlobalData::ms_pStack->aEmerStop = 0;
            //writeKgLogfile(QString("step4 EmerStopState pStack->usEmerStopState=%1").arg(KgGlobalData::ms_pStack->usEmerStopState));
        }
        //KgGlobalData::ms_pStack->aEmerStop = m_emergStopAlarm;
        KgGlobalData::ms_pStack->aEnvTemp[21] = m_emergStopAlarm;
    }
}

void DryCtrlThread::judgeEmergeStopSec()
{
    QString strContextCn = "";
    QString strContextEn = "";
    if (KgGlobalData::ms_emgStopStrategySec.diList.size() > 0) // 有采集急停信号
    {

        QString strPos;
        if (HasAlarmVal(KgGlobalData::ms_emgStopStrategySec, KgGlobalData::ms_dryData.DIVal,3,strPos))
        {
            if (++m_emergStopCountSec  >= KgGlobalData::ms_emgStopStrategySec.confirmedCount)
            {
                if (0 == m_emergStopAlarmSec)
                {
                    strContextCn = KgGlobalData::ms_emgStopStrategySec.diName + QString("(DI%1).").arg(strPos);
                    strContextEn = KgGlobalData::ms_emgStopStrategySec.diName_EN + QString("(DI%1).").arg(strPos);
                    saveLogToBaDb(strContextCn, strContextEn);
                }
                m_emergStopAlarmSec  = 1;
                sendLog(0, QString("******************2# EmergStopAlarm(DI%1)").arg(strPos));
            }

            limitAlmCount(m_emergStopCountSec);
        }
        else
        {
            if (1 == m_emergStopAlarmSec)
            {
                strContextCn = KgGlobalData::ms_emgStopStrategySec.diOverName;
                strContextEn = KgGlobalData::ms_emgStopStrategySec.diOverName_EN;
                saveLogToBaDb(strContextCn, strContextEn);
            }
            m_emergStopCountSec = 0;
            m_emergStopAlarmSec = 0;
            m_emergStopSignalSec = 0;
            //sendLog(0, "emergStopAlarm is 0");
        }

        if (m_emergStopAlarmSec) // 发生急停
        {
            //KgGlobalData::ms_pStack->usEmerStopState = 1;
            //KgGlobalData::ms_pStack->aEmerStop = 1;
            //writeKgLogfile(QString("step3 EmerStopState pStack->usEmerStopState=%1").arg(KgGlobalData::ms_pStack->usEmerStopState));
        }
        else       // 正常
        {
            //KgGlobalData::ms_pStack->usEmerStopState = 2;
            //KgGlobalData::ms_pStack->aEmerStop = 0;
            //writeKgLogfile(QString("step4 EmerStopState pStack->usEmerStopState=%1").arg(KgGlobalData::ms_pStack->usEmerStopState));
        }
        // KgGlobalData::ms_pStack->aEmerStop = m_emergStopAlarm;
        KgGlobalData::ms_pStack->aEnvTemp[11] = m_emergStopAlarmSec;
    }
}

void DryCtrlThread::judgeBmsLocalState()// added 2023-12-25
{
    QString strContextCn = "";
    QString strContextEn = "";
    if (KgGlobalData::ms_bmsLocalStrategy.diList.size() > 0)
    {
        QString strPos;
        if (HasAlarmVal(KgGlobalData::ms_bmsLocalStrategy, KgGlobalData::ms_dryData.DIVal,3,strPos))
        {
            if (++m_bmsLocalCount >= KgGlobalData::ms_bmsLocalStrategy.confirmedCount)
            {
                if (0 == m_bmsLocalState)
                {
                    strContextCn = KgGlobalData::ms_bmsLocalStrategy.diName + QString("(DI%1).").arg(strPos);
                    strContextEn = KgGlobalData::ms_bmsLocalStrategy.diName_EN + QString("(DI%1).").arg(strPos);
                    saveLogToBaDb(strContextCn, strContextEn);
                }
                m_bmsLocalState  = 1;
                sendLog(0, QString("******************Bms is local state(DI%1)").arg(strPos));
            }

            limitAlmCount(m_bmsLocalCount);
        }
        else
        {
            if (1 == m_bmsLocalState)
            {
                strContextCn = KgGlobalData::ms_bmsLocalStrategy.diOverName;
                strContextEn = KgGlobalData::ms_bmsLocalStrategy.diOverName_EN;
                saveLogToBaDb(strContextCn, strContextEn);
            }
            m_bmsLocalCount = 0;
            m_bmsLocalState = 0;
            m_bmsLocalSignal = 0;
        }
        KgGlobalData::ms_pStack->aEnvTemp[19] = m_bmsLocalState;
    }
}

void DryCtrlThread::judgeBmsRemoteState()
{
    QString strContextCn = "";
    QString strContextEn = "";
    if (KgGlobalData::ms_bmsRemmoteStrategy.diList.size() > 0)
    {
        QString strPos;
        if (HasAlarmVal(KgGlobalData::ms_bmsRemmoteStrategy, KgGlobalData::ms_dryData.DIVal,3,strPos))
        {
            if (++m_bmsRemoteCount >= KgGlobalData::ms_bmsRemmoteStrategy.confirmedCount)
            {
                if (0 == m_bmsRemoteState)
                {
                    strContextCn = KgGlobalData::ms_bmsRemmoteStrategy.diName + QString("(DI%1).").arg(strPos);
                    strContextEn = KgGlobalData::ms_bmsRemmoteStrategy.diName_EN + QString("(DI%1).").arg(strPos);
                    saveLogToBaDb(strContextCn, strContextEn);
                }
                m_bmsRemoteState  = 1;
                sendLog(0, QString("******************Bms is remote state(DI%1)").arg(strPos));
            }

            limitAlmCount(m_bmsRemoteCount);
        }
        else
        {
            if (1 == m_bmsRemoteState)
            {
                strContextCn = KgGlobalData::ms_bmsRemmoteStrategy.diOverName;
                strContextEn = KgGlobalData::ms_bmsRemmoteStrategy.diOverName_EN;
                saveLogToBaDb(strContextCn, strContextEn);
            }
            m_bmsRemoteCount = 0;
            m_bmsRemoteState = 0;
            m_bmsRemoteSignal = 0;
        }
        KgGlobalData::ms_pStack->aEnvTemp[20] = m_bmsRemoteState;
    }
}

// added 2022-3-27
void DryCtrlThread::judgeFuseAlarm()
{
    QString strContextCn = "";
    QString strContextEn = "";
    if (KgGlobalData::ms_fuseStrategy.diList.size() > 0)  // 有采集熔断器信号
    {
        QString strPos;
        if (HasAlarmVal(KgGlobalData::ms_fuseStrategy, KgGlobalData::ms_dryData.DIVal,4,strPos))
        {
            if (++m_fuseCount >= KgGlobalData::ms_fuseStrategy.confirmedCount)
            {
                if (0 == m_fuseAlarm)
                {
                    strContextCn = KgGlobalData::ms_fuseStrategy.diName + QString("(DI%1).").arg(strPos);
                    strContextEn = KgGlobalData::ms_fuseStrategy.diName_EN + QString("(DI%1).").arg(strPos);
                    saveLogToBaDb(strContextCn, strContextEn);
                }
                m_fuseAlarm  = 1;
                sendLog(0, QString("******************FuseAlarm(DI%1)").arg(strPos));
            }

            limitAlmCount(m_fuseCount);
        }
        else
        {
            if (1 == m_fuseAlarm)
            {
                strContextCn = KgGlobalData::ms_fuseStrategy.diOverName;
                strContextEn = KgGlobalData::ms_fuseStrategy.diOverName_EN;
                saveLogToBaDb(strContextCn, strContextEn);
            }
            m_fuseCount = 0;
            m_fuseAlarm = 0;
            m_fuseSignal = 0;
            //sendLog(0, "fuseAlarm is 0");
        }
        KgGlobalData::ms_pStack->aEnvTemp[17] = m_fuseAlarm;
    }
}

// 读取消防释放告警 // added 2022-4-6
void DryCtrlThread::judgeXfMotionMsg()
{
    QString strContextCn = "";
    QString strContextEn = "";
    if (KgGlobalData::ms_xfMotionStrategy.diList.size() > 0)
    {
        QString strPos;
        if (HasAlarmVal(KgGlobalData::ms_xfMotionStrategy, KgGlobalData::ms_dryData.DIVal, 5, strPos))
        {
            if (++m_xfMotionCount >= KgGlobalData::ms_xfMotionStrategy.confirmedCount)
            {
                if (0 == m_xfMotionAlarm)
                {
                    strContextCn = KgGlobalData::ms_xfMotionStrategy.diName + QString("(DI%1).").arg(strPos);
                    strContextEn = KgGlobalData::ms_xfMotionStrategy.diName_EN + QString("(DI%1).").arg(strPos);
                    saveLogToBaDb(strContextCn, strContextEn);
                }
                m_xfMotionAlarm = 1;
                sendLog(0, QString("******************Fire motion Alarm(DI%1)").arg(strPos));
            }

            limitAlmCount(m_xfMotionCount);
        }
        else
        {
            if (1 == m_xfMotionAlarm)
            {
                strContextCn = KgGlobalData::ms_xfMotionStrategy.diOverName;
                strContextEn = KgGlobalData::ms_xfMotionStrategy.diOverName_EN;
                saveLogToBaDb(strContextCn, strContextEn);
            }
            m_xfMotionCount = 0;
            m_xfMotionAlarm = 0;
        }

        KgGlobalData::ms_pStack->aFireAction = m_xfMotionAlarm; // modified 2023-3-13

#ifdef ND_VER_PROGRAM 	// 南都版本 
        if (m_xfMotionAlarm) // 消防释放
        {
            KgGlobalData::ms_pStack->usStackTotAlarm = KgGlobalData::ms_pStack->usStackTotAlarm | (1 << 7);
        }
        else  // 正常
        {
            KgGlobalData::ms_pStack->usStackTotAlarm = KgGlobalData::ms_pStack->usStackTotAlarm & (~(1 << 7));
        }
        //printf("===============================usStackTotAlarm %d\n", KgGlobalData::ms_pStack->usStackTotAlarm);
#endif
    }
}

// 读取消防预警信号 // added 2022-6-8
void DryCtrlThread::judgeXfWarmMsg()
{
    QString strContextCn = "";
    QString strContextEn = "";
    bool bHasWarm = 0;
    if (KgGlobalData::ms_xfWarmStrategy.diList.size() > 0)
    {
        bHasWarm = 1;
        QString strPos;
        if (HasAlarmVal(KgGlobalData::ms_xfWarmStrategy, KgGlobalData::ms_dryData.DIVal, 6, strPos))
        {
            if (++m_xfWarmCount >= KgGlobalData::ms_xfWarmStrategy.confirmedCount)
            {
                if (0 == m_xfWarmMsg)
                {
                    strContextCn = KgGlobalData::ms_xfWarmStrategy.diName + QString("(DI%1).").arg(strPos);
                    strContextEn = KgGlobalData::ms_xfWarmStrategy.diName_EN + QString("(DI%1).").arg(strPos);
                    saveLogToBaDb(strContextCn, strContextEn);
                }
                m_xfWarmMsg = 1;
                sendLog(0, QString("******************Fire warm(DI%1)").arg(strPos));
            }

            limitAlmCount(m_xfWarmCount);
        }
        else
        {
            if (1 == m_xfWarmMsg)
            {
                strContextCn = KgGlobalData::ms_xfWarmStrategy.diOverName;
                strContextEn = KgGlobalData::ms_xfWarmStrategy.diOverName_EN;
                saveLogToBaDb(strContextCn, strContextEn);
            }
            m_xfWarmCount = 0;
            m_xfWarmMsg = 0;
        }

        //KgGlobalData::ms_pStack->aEnvFireWarn = m_xfWarmMsg;
        KgGlobalData::ms_pStack->aFireWarn = m_xfWarmMsg; // 消防预警
        KgGlobalData::ms_pStack->aEnvTemp[14] = m_xfWarmMsg;
    }
}

void DryCtrlThread::judgeUpsAlarm()
{
    QString strContextCn = "";
    QString strContextEn = "";
    if (KgGlobalData::ms_upsAlmStrategy.diList.size() > 0)
    {
        QString strPos;
        if (HasAlarmVal(KgGlobalData::ms_upsAlmStrategy, KgGlobalData::ms_dryData.DIVal, 7, strPos))
        {
            if (++m_upsAlarmCount >= KgGlobalData::ms_upsAlmStrategy.confirmedCount)
            {
                if (0 == m_upsAlarm)
                {
                    strContextCn = KgGlobalData::ms_upsAlmStrategy.diName + QString("(DI%1).").arg(strPos);
                    strContextEn = KgGlobalData::ms_upsAlmStrategy.diName_EN + QString("(DI%1).").arg(strPos);
                    saveLogToBaDb(strContextCn, strContextEn);
                }
                m_upsAlarm = 1;
                sendLog(0, QString("******************UPS Fault(DI%1)").arg(strPos));
            }

            limitAlmCount(m_upsAlarmCount);
        }
        else
        {
            if (1 == m_upsAlarm)//if (1 == m_xfWarmMsg)// 2024-4-24
            {
                strContextCn = KgGlobalData::ms_upsAlmStrategy.diOverName;
                strContextEn = KgGlobalData::ms_upsAlmStrategy.diOverName_EN;
                saveLogToBaDb(strContextCn, strContextEn);
            }
            m_upsAlarmCount = 0;
            m_upsAlarm = 0;
        }
        KgGlobalData::ms_pStack->aEnvTemp[16] = m_upsAlarm;
    }
}

void DryCtrlThread::judgeDoorAlarm()
{
    QString strContextCn = "";
    QString strContextEn = "";
    if (KgGlobalData::ms_doorAlmStrategy.diList.size() > 0)
    {
        QString strPos;
        if (HasAlarmVal(KgGlobalData::ms_doorAlmStrategy, KgGlobalData::ms_dryData.DIVal, 8, strPos))
        {
            if (++m_doorAlarmCount >= KgGlobalData::ms_doorAlmStrategy.confirmedCount)
            {
                if (0 == m_doorAlarm)
                {
                    strContextCn = KgGlobalData::ms_doorAlmStrategy.diName + QString("(DI%1).").arg(strPos);
                    strContextEn = KgGlobalData::ms_doorAlmStrategy.diName_EN + QString("(DI%1).").arg(strPos);
                    saveLogToBaDb(strContextCn, strContextEn);
                }
                m_doorAlarm = 1;
                sendLog(0, QString("******************Door Alarm(DI%1)").arg(strPos));
            }

            limitAlmCount(m_doorAlarmCount);
        }
        else
        {
            if (1 == m_doorAlarm)
            {
                strContextCn = KgGlobalData::ms_doorAlmStrategy.diOverName;
                strContextEn = KgGlobalData::ms_doorAlmStrategy.diOverName_EN;
                saveLogToBaDb(strContextCn, strContextEn);
            }
            m_doorAlarmCount = 0;
            m_doorAlarm = 0;
        }
        //sendLog(0, QString("******************aAcceCtrlState:%1").arg((int)KgGlobalData::ms_pStack->aAcceCtrlState));
        KgGlobalData::ms_pStack->aAcceCtrlState = m_doorAlarm;       // 门禁状态
    }
}

void DryCtrlThread::judgeDoorAlarmSec()
{
    QString strContextCn = "";
    QString strContextEn = "";
    if (KgGlobalData::ms_doorAlmStrategySec.diList.size() > 0)
    {
        QString strPos;
        if (HasAlarmVal(KgGlobalData::ms_doorAlmStrategySec, KgGlobalData::ms_dryData.DIVal, 8, strPos))
        {
            if (++m_doorAlarmCountSec >= KgGlobalData::ms_doorAlmStrategySec.confirmedCount)
            {
                if (0 == m_doorAlarmSec)
                {
                    strContextCn = KgGlobalData::ms_doorAlmStrategySec.diName + QString("(DI%1).").arg(strPos);
                    strContextEn = KgGlobalData::ms_doorAlmStrategySec.diName_EN + QString("(DI%1).").arg(strPos);
                    saveLogToBaDb(strContextCn, strContextEn);
                }
                m_doorAlarmSec = 1;
                sendLog(0, QString("******************2# Door Alarm(DI%1)").arg(strPos));
            }

            limitAlmCount(m_doorAlarmCountSec);
        }
        else
        {
            if (1 == m_doorAlarmSec)
            {
                strContextCn = KgGlobalData::ms_doorAlmStrategySec.diOverName;
                strContextEn = KgGlobalData::ms_doorAlmStrategySec.diOverName_EN;
                saveLogToBaDb(strContextCn, strContextEn);
            }
            m_doorAlarmCountSec = 0;
            m_doorAlarmSec = 0;
        }
        //writeKgLogfile(QString("||||||||||||||||aStackTemp[4]=====:%1").arg((int)KgGlobalData::ms_pStack->aStackTemp[4]));
        //KgGlobalData::ms_pStack->aStackTemp[4] = m_doorAlarmSec;       // 门禁状态2
        KgGlobalData::ms_pStack->aEnvTemp[10] = m_doorAlarmSec;
    }
}

void DryCtrlThread::judgeAcFault()
{
    QString strContextCn = "";
    QString strContextEn = "";
    if (KgGlobalData::ms_acFaultStrategy.diList.size() > 0)
    {
        QString strPos;
        if (HasAlarmVal(KgGlobalData::ms_acFaultStrategy, KgGlobalData::ms_dryData.DIVal, 7, strPos))
        {
            if (++m_acFaultCount >= KgGlobalData::ms_acFaultStrategy.confirmedCount)
            {
                if (0 == m_acFault)
                {
                    strContextCn = KgGlobalData::ms_acFaultStrategy.diName + QString("(DI%1).").arg(strPos);
                    strContextEn = KgGlobalData::ms_acFaultStrategy.diName_EN + QString("(DI%1).").arg(strPos);
                    saveLogToBaDb(strContextCn, strContextEn);
                }
                m_acFault = 1;
                sendLog(0, QString("******************AC Fault(DI%1)").arg(strPos));
            }

            limitAlmCount(m_acFaultCount);
        }
        else
        {
            if (1 == m_acFault)
            {
                strContextCn = KgGlobalData::ms_acFaultStrategy.diOverName;
                strContextEn = KgGlobalData::ms_acFaultStrategy.diOverName_EN;
                saveLogToBaDb(strContextCn, strContextEn);
            }
            m_acFaultCount = 0;
            m_acFault = 0;
        }
    }
}

void DryCtrlThread::judgeLqFault()
{
    QString strContextCn = "";
    QString strContextEn = "";
    if (KgGlobalData::ms_lqFaultStrategy.diList.size() > 0)
    {
        QString strPos;
        if (HasAlarmVal(KgGlobalData::ms_lqFaultStrategy, KgGlobalData::ms_dryData.DIVal, 7, strPos))
        {
            if (++m_lqFaultCount >= KgGlobalData::ms_lqFaultStrategy.confirmedCount)
            {
                if (0 == m_lqFault)
                {
                    strContextCn = KgGlobalData::ms_lqFaultStrategy.diName + QString("(DI%1).").arg(strPos);
                    strContextEn = KgGlobalData::ms_lqFaultStrategy.diName_EN + QString("(DI%1).").arg(strPos);
                    saveLogToBaDb(strContextCn, strContextEn);
                }
                m_lqFault = 1;
                sendLog(0, QString("******************LQ Fault(DI%1)").arg(strPos));
            }

            limitAlmCount(m_lqFaultCount);
        }
        else
        {
            if (1 == m_lqFault)
            {
                strContextCn = KgGlobalData::ms_lqFaultStrategy.diOverName;
                strContextEn = KgGlobalData::ms_lqFaultStrategy.diOverName_EN;
                saveLogToBaDb(strContextCn, strContextEn);
            }
            m_lqFaultCount = 0;
            m_lqFault = 0;
        }
    }
}

// 2023-11-11 整理处理8个备用信号合并成1个
void DryCtrlThread::judgetResState()
{
    QString strContextCn = "";
    QString strContextEn = "";
    for (int index = 0; index < RES_STRATEGY_COUNT; ++index)
    {
        XFStrategy &resStg = KgGlobalData::ms_resStrategy[index];
        if (resStg.diList.size() > 0)
        {
            QString strPos;
            if (HasAlarmVal(resStg, KgGlobalData::ms_dryData.DIVal, 8, strPos))
            {
                m_reservedCount[index] += 1;
                if (m_reservedCount[index] >= KgGlobalData::ms_doorAlmStrategy.confirmedCount)
                {
                    if (0 == m_reservedAlarm[index])
                    {
                        strContextCn = resStg.diName + QString("(DI%1).").arg(strPos);
                        strContextEn = resStg.diName_EN + QString("(DI%1).").arg(strPos);
                        saveLogToBaDb(strContextCn, strContextEn);
                    }
                    m_reservedAlarm[index] = 1;
                    sendLog(0, QString("******************Reserved Alarm%1(DI%2)").arg(index+1).arg(strPos));
                }

                limitAlmCount(m_reservedCount[index]);
            }
            else
            {
                if (1 == m_reservedAlarm[index])
                {
                    strContextCn = resStg.diOverName;
                    strContextEn = resStg.diOverName_EN;
                    saveLogToBaDb(strContextCn, strContextEn);
                }
                m_reservedCount[index] = 0;
                m_reservedAlarm[index] = 0;
            }
            KgGlobalData::ms_pStack->aEnvTemp[index] = m_reservedAlarm[index];
        }
    }
}

// added 2021-12-28
// 判断是否有可燃气体信号，如有BAMS立即停机
bool DryCtrlThread::hasCombusGasAlarm()
{
    bool bEnabledAlarm = false; // 不使能 云浮1期只需将可燃气体信号传给后台，BA不需要做逻辑

    if (bEnabledAlarm)
    {
        return m_combusGasAlarm;
    }
    else
    {
        return 0;
    }
}

void DryCtrlThread::judgeCombusGasAlarm()
{
    QString strContextCn = "";
    QString strContextEn = "";

    if (KgGlobalData::ms_combusGasStrategy.diList.size() > 0) // 有采集可燃气体信号
    {
        QString strPos;
        if (HasAlarmVal(KgGlobalData::ms_combusGasStrategy, KgGlobalData::ms_dryData.DIVal,1,strPos))
        {
            if (++m_combusGasCount >= KgGlobalData::ms_combusGasStrategy.confirmedCount)
            {
                if (0 == m_combusGasAlarm)
                {
                    strContextCn = KgGlobalData::ms_combusGasStrategy.diName + QString("(DI%1).").arg(strPos);
                    strContextEn = KgGlobalData::ms_combusGasStrategy.diName_EN + QString("(DI%1).").arg(strPos);
                    saveLogToBaDb(strContextCn, strContextEn);
                }
                //if (999 == KgGlobalData::ms_pStack->usFireBankAddr)
                //    m_combusGasAlarm  = 1;
                //else
                //	 m_combusGasDetectAlarm = 1;
                m_combusGasAlarm  = 1;
                sendLog(0, QString("******************Combustible Gas Alarm(DI%1)").arg(strPos));
            }

            limitAlmCount(m_combusGasCount);
        }
        else
        {
            if (1 == m_combusGasAlarm)
            {
                strContextCn = KgGlobalData::ms_combusGasStrategy.diOverName;
                strContextEn = KgGlobalData::ms_combusGasStrategy.diOverName_EN;
                saveLogToBaDb(strContextCn, strContextEn);
            }
            m_combusGasCount = 0;
            m_combusGasAlarm = 0;
            m_combusGasDetectAlarm = 0;
            m_combusGasSignal = 0;
        }

        KgGlobalData::ms_pStack->aGasAlarm = m_combusGasAlarm;        // 可燃气体
    }
}

quint16 DryCtrlThread::getIsolSwitchAggrState()
{
    // 有配置隔离开关策略, 才检查隔离开关是否都闭合
    if (KgGlobalData::ms_isolSwitchStrategy.diList.size() == 0)
    {
        return 0;
    }

    int closedCount = 0;
    int openedCount = 0;
    int totalCount = 0;
    for (int k = 0; k < KgGlobalData::ms_isolSwitchStrategy.diList.size(); ++k)
    {
        if (isBankInStack(k)) // 第k簇投入
        {
            totalCount += 1;
            DI_STU diStu = KgGlobalData::ms_isolSwitchStrategy.diList[k];
            int maskVal = (1 << diStu.diIndex);
            int tmpState = 0;
            if (maskVal == (maskVal & KgGlobalData::ms_dryData.DIVal)) // 第k簇的隔离开关闭合
            {
                closedCount += 1;
                tmpState = 1;
            }
            else
            {
                openedCount += 1;
            }

            if (1 == KgGlobalData::ms_saveHlkgLog)
            {

            }
        }
    }

    if (closedCount > 0 && closedCount == totalCount) // 隔离开关都闭合
    {
        return 1;
    }
    else
    {
        return 0;
    }
}

quint16 DryCtrlThread::getConfSwitchState()
{
    int iClosedCount = 0;
    int iOpenedCount = 0;
    int totalCount = 0;

    // 有采集汇流开关反馈, 才检查汇流开关是否都闭合
    if (KgGlobalData::ms_hlkgStrategy.diCfgList.size() == 0)
    {
        return 0;
    }

    for (int k = 0; k < KgGlobalData::ms_hlkgStrategy.diCfgList.size(); ++k)
    {
        DI_STU diStu = KgGlobalData::ms_hlkgStrategy.diCfgList[k];
        int tmpState = getConfSwitchState(KgGlobalData::ms_pStack, diStu);

        totalCount += 1;

        if (1 == tmpState)
        {
            iClosedCount += 1;
        }
        else
        {
            iOpenedCount += 1;
        }
    }

    if (iClosedCount > 0 && iClosedCount == totalCount)
    {
        return 1;
    }
    else
    {
        return 0;
    }
}

void DryCtrlThread::judgetConfSwitchState(CBattStack *pStack)
{
    int iClosedCount = 0;
    int iOpenedCount = 0;
    int totalCount = 0;
    QString strContextCn = "";
    QString strContextEn = "";

    if (0 == KgGlobalData::ms_hlkgStrategy.diCfgList.size())
    {
        return;
    }

    // 有采集汇流开关反馈, 才检查汇流开关是否都闭合
    // deleted 2022-3-26
    //if (KgGlobalData::ms_hlkgStrategy.diCfgList.size() == 0)
    //{
    //	return;
    //}

    //if (KgGlobalData::ms_hlkgStrategy.diCfg.diIndex < KgGlobalData::ms_devDiCount) // 有采集汇流开关反馈
    for (int k = 0; k < KgGlobalData::ms_hlkgStrategy.diCfgList.size(); ++k)
    {
        DI_STU diStu = KgGlobalData::ms_hlkgStrategy.diCfgList[k];
        int tmpState = getConfSwitchState(pStack, diStu);

        totalCount += 1;

        //if (hlkgMask == (hlkgMask & g_DIState))   //DI1值为1，汇流开关闭合
        if (1 == tmpState)
        {
            sendLog(0, QString("***Hlkg%1 Has HZ.").arg(k+1));
            iClosedCount += 1;
            // modified 2022-7-11
            /*
			if (0 == k) // added 2022-05-25
				pStack->usDI1 = 1; 
			else if (1 == k)
				pStack->usDI2 = 1;
			else if (2 == k)
				pStack->usDI3 = 1;
			else;
			*/
            //pStack->usDI2 = 1;
        }
        else
        {
            sendLog(0, QString("***Hlkg%1 Has FZ.").arg(k+1));
            iOpenedCount += 1;
            /*
			if (0 == k) // added 2022-05-25
				pStack->usDI1 = 0;
			else if (1 == k)
				pStack->usDI2 = 0;
			else if (2 == k)
				pStack->usDI3 = 0;
			else;
			*/
            //pStack->usDI2 = 0;
        }

        // 与BA主程序日志重复,汇流开关策略不是200时才输出 // modified 2022-11-18
        //if (1 == KgGlobalData::ms_saveHlkgLog && 200 != pStack->usConfSwitchStrategy)
        if (1 == KgGlobalData::ms_saveHlkgLog && 3 != pStack->usConfSwitchStrategy)
        {
            if ((0 == m_hlkgState[k]) && 1 == tmpState)     // || 99 == m_hlkgState
            {
                if (1 == KgGlobalData::ms_hlkgStrategy.diCfgList.size())
                {
                    strContextCn = "汇流开关合闸.";
                    strContextEn = QString("ConfSwitch is closed.");
                }
                else
                {
                    strContextCn = QString("%1#").arg(k+1) + ("汇流开关合闸.");
                    strContextEn = QString("%1# ConfSwitch is closed.").arg(k+1);
                }
                saveLogToBaDb(strContextCn, strContextEn);
            }
            else if ((1 == m_hlkgState[k]) && 0 == tmpState) // || 99 == m_hlkgState
            {
                if (1 == KgGlobalData::ms_hlkgStrategy.diCfgList.size())
                {
                    strContextCn = "汇流开关分闸.";
                    strContextEn = QString("ConfSwitch is opened.");
                }
                else
                {
                    strContextCn = QString("%1#").arg(k+1) + ("汇流开关分闸.");
                    strContextEn = QString("%1# ConfSwitch is opened.").arg(k+1);
                }
                saveLogToBaDb(strContextCn, strContextEn);
            }
            else
                ;
        }

        m_hlkgState[k] = tmpState;
    }

    if (iClosedCount > 0 && iClosedCount == totalCount)
    {
#ifdef MASTER_VER
        //if (3 == pStack->usConfSwitchStrategy)// 汇流开关策略 200 - 3rd进程设定 汇流开关断开,才能闭合接触器 // deleted 2023-12-13
        {
            pStack->usConfSwitchState = 1;//通知BA 汇流开关已经闭合
            pStack->aConfSwitchState = 1;
        }
        //pStack->usDI2 = 1;// deleted 2022-11-16
#else
        keepContCtrlOpened(pStack->usStackState,1);
#endif \
        //pStack->usStackTemp[2] = 1; // 堆级断路器状态反馈信号 0--断开 1--闭合
    }
    else
    {
#ifdef MASTER_VER
        //if (3 == pStack->usConfSwitchStrategy)
        {
            pStack->usConfSwitchState = 2;//通知BA 汇流开关已经断开
            pStack->aConfSwitchState = 0;
        }
        //pStack->usDI2 = 0; // deleted 2022-11-16
        //pStack->usStackTemp[2] = 0; // 堆级断路器状态反馈信号 0--断开 1--闭合
#else
        keepContCtrlOpened(pStack->usStackState,0);
#endif	
    }
}

int g_isolSwitchClosedSignal = 0;
int g_isolSwitchOpenedSignal = 0;
int g_oldIsolSwitchAggrState = 99;
void DryCtrlThread::judgeIsolSwitchAggrState()
{
    QString strContextCn = "";
    QString strContextEn = "";
#ifdef LSZH_PRJ  //added 2021-5-13
    if ((0x0F & KgGlobalData::ms_dryData.DIVal) == 0x0) // 4个断路器都没有脱扣
    {
        m_emergStopAlarm = 0;
    }
    else // 有断路器脱扣
    {
        if (m_emergStopCount < 1000)
        {
            m_emergStopCount += 1;
        }

        if (m_emergStopCount >= 16) // 断路器断开维持20秒
        {
            if (0 == m_emergStopAlarm)
            {
                sprintf(m_tmpBuf,"检测到断路器脱扣(%d)，控制系统急停!", KgGlobalData::ms_dryData.DIVal);
                saveLogToBaDb(kgConvert(m_tmpBuf));
                m_emergStopAlarm = 1; // 通过急停告之BA跳机
            }
        }
    }
#endif

    // 有配置隔离开关策略, 才检查隔离开关是否都闭合
    if (KgGlobalData::ms_isolSwitchStrategy.diList.size() == 0)
    {
        return;
    }
    KgGlobalData::ms_pStack->usIsolSwitchStrategy = 200; // added 2024-6-8

    int closedCount = 0;
    int openedCount = 0;
    int totalCount = 0;
    for (int k = 0; k < KgGlobalData::ms_isolSwitchStrategy.diList.size(); ++k)
    {
        if (isBankInStack(k)) // 第k簇投入
        {
            totalCount += 1;
            DI_STU diStu = KgGlobalData::ms_isolSwitchStrategy.diList[k];
            int maskVal = (1 << diStu.diIndex);
            int tmpState = 0;
            if (maskVal == (maskVal & KgGlobalData::ms_dryData.DIVal)) // 第k簇的隔离开关闭合
            {
                closedCount += 1;
                tmpState = 1;
            }
            else
            {
                openedCount += 1;
            }

            if (1 == KgGlobalData::ms_saveHlkgLog)
            {
                if ((0 == m_glkgState[k]) && 1 == tmpState)     // || 99 == m_hlkgState
                {
                    if (1 == KgGlobalData::ms_isolSwitchStrategy.diList.size())
                    {
                        strContextCn = "隔离开关闭合.";
                        strContextEn = QString("IsolSwitch is closed.");
                    }
                    else
                    {
                        strContextCn = QString("%1#").arg(k+1) +"隔离开关闭合.";
                        strContextEn = QString("%1# IsolSwitch is closed.").arg(k+1);
                    }
                    saveLogToBaDb(strContextCn, strContextEn);
                }
                else if ((1 == m_glkgState[k]) && 0 == tmpState)
                {
                    if (1 == KgGlobalData::ms_isolSwitchStrategy.diList.size())
                    {
                        strContextCn = "隔离开关断开.";
                        strContextEn = QString("IsolSwitch is opened.");
                    }
                    else
                    {
                        strContextCn = QString("%1#").arg(k+1) +"隔离开关断开.";
                        strContextEn = QString("%1# IsolSwitch is opened.").arg(k+1);
                    }
                    saveLogToBaDb(strContextCn, strContextEn);
                }
                else
                    ;
            }

            m_glkgState[k] = tmpState;
        }
    }

    if (closedCount > 0 && closedCount == totalCount) // 隔离开关都闭合
    //if (closedCount > 0) // 至少有一个隔离开关闭合
    {
        m_isolSwitchOpendCount = 0;
        g_isolSwitchOpenedSignal = 0;
        if (m_isolSwitchClosedCount < 1000)
        {
            m_isolSwitchClosedCount += 1;
        }
        if (m_isolSwitchClosedCount >= KgGlobalData::ms_isolSwitchStrategy.confirmedCount)
        {
            SetIsolSwitchAggrState(1);
            if (1 != g_oldIsolSwitchAggrState)// added 2021-07-17
            {
                g_oldIsolSwitchAggrState = 1;
                strContextCn = QString("隔离开关闭合:") + QString("%1.").arg(KgGlobalData::ms_dryData.DIVal);
                strContextEn = QString("All IsolSwitch is closed:%1.").arg(KgGlobalData::ms_dryData.DIVal);
                saveLogToBaDb(strContextCn, strContextEn);
            }
        }
    }
    else
    {
        m_isolSwitchClosedCount = 0;
        g_isolSwitchClosedSignal = 0;
        if (m_isolSwitchOpendCount < 1000)
        {
            m_isolSwitchOpendCount += 1;
        }
        if (m_isolSwitchOpendCount >= KgGlobalData::ms_isolSwitchStrategy.confirmedCount)
        {
            SetIsolSwitchAggrState(0);
            if (0 != g_oldIsolSwitchAggrState)// added 2021-07-17
            {
                g_oldIsolSwitchAggrState = 0;
                strContextCn = QString("隔离开关断开:") + QString("%1.").arg(KgGlobalData::ms_dryData.DIVal);
                strContextEn = QString("All IsolSwitch is opened:%1.").arg(KgGlobalData::ms_dryData.DIVal);
                saveLogToBaDb(strContextCn, strContextEn);
            }
        }
    }
    /*
#ifdef GSHT_PRJ //added 2021-5-27
     int closedCount = 0;
     int openedCount = 0;
	 for (int k = 0; k < 2; ++k) // 检查断路器1和2是否闭合
	 {
		if (isBankInStack(0))
		{
	        // 一直只判断第一簇，不对 现场测试只要第一簇合上，BA就会正常,这不对 2021-7-17
			if (1 == (1&g_DIState)) // 断路器闭合 
			{
				closedCount += 1;
			}
			else
			{
				openedCount += 1;
			}
		}
	}

	if (closedCount > 0 && openedCount == 0) // 都闭合
	{
		SetIsolSwitchAggrState(1);
	}
	else
	{
		SetIsolSwitchAggrState(0);
	}
#endif
*/
}

void DryCtrlThread::judgeMainSwitchState()
{
    QString strContextCn = "";
    QString strContextEn = "";
    if (KgGlobalData::ms_mainSwitchStrategy.diList.size() > 0)
    {
        QString strPos;

        if (HasAlarmVal(KgGlobalData::ms_mainSwitchStrategy, KgGlobalData::ms_dryData.DIVal,1,strPos))
        {
            if (++m_mainSwitchCount >= KgGlobalData::ms_mainSwitchStrategy.confirmedCount)
            {
                if (0 == m_mainSwitchClosed)
                {
                    strContextCn = KgGlobalData::ms_mainSwitchStrategy.diName + QString("(DI%1).").arg(strPos);
                    strContextEn = KgGlobalData::ms_mainSwitchStrategy.diName_EN + QString("(DI%1).").arg(strPos);
                    saveLogToBaDb(strContextCn, strContextEn);
                }
                m_mainSwitchClosed  = 1;
                sendLog(0, QString("******************Main switch is closed(DI%1)").arg(strPos));
            }

            limitAlmCount(m_mainSwitchCount);
        }
        else
        {
            if (1 == m_mainSwitchClosed)
            {
                strContextCn = KgGlobalData::ms_mainSwitchStrategy.diOverName;
                strContextEn = KgGlobalData::ms_mainSwitchStrategy.diOverName_EN;
                saveLogToBaDb(strContextCn, strContextEn);
            }

            m_mainSwitchCount = 0;
            m_mainSwitchClosed = 0;
        }

        KgGlobalData::ms_pStack->aEnvTemp[22] = m_mainSwitchClosed;
    }
}

void DryCtrlThread::judgeChgJcqState()
{
    QString strContextCn = "";
    QString strContextEn = "";
    if (KgGlobalData::ms_diIndexChgDrive < KgGlobalData::ms_devDiCount) // 有充电接触器反馈
    {
        int hlkgMask = 1 << KgGlobalData::ms_diIndexChgDrive;
        int newChgJcqState = 0;
        if (hlkgMask == (hlkgMask & KgGlobalData::ms_dryData.DIVal))//DI1值为1，汇流开关闭合
        {
            newChgJcqState = 1;// 充电接触器已经闭合
        }

        if (1 == newChgJcqState  && 0 == m_usOldChgJcqState)
        {
            strContextCn = "充电接触器闭合.";
            strContextEn = QString("Charge contactor is closed.");
            saveLogToBaDb(strContextCn, strContextEn);
        }

        if (0 == newChgJcqState  && 1 == m_usOldChgJcqState)
        {
            strContextCn = "充电接触器断开.";
            strContextEn = QString("Charge contactor is opened.");
            saveLogToBaDb(strContextCn, strContextEn);
        }
        m_usOldChgJcqState = newChgJcqState;
    }

    if (KgGlobalData::ms_diIndexDchgDrive < KgGlobalData::ms_devDiCount) // 有放电接触器反馈
    {
        int hlkgMask = 1 << KgGlobalData::ms_diIndexDchgDrive;
        int newDchgJcqState = 0;
        if (hlkgMask == (hlkgMask & KgGlobalData::ms_dryData.DIVal))
        {
            newDchgJcqState = 1;// 放电接触器已经闭合
        }

        if (1 == newDchgJcqState  && 0 == m_usOldDchgJcqState)
        {
            strContextCn = "放电接触器闭合.";
            strContextEn = QString("Discharge contactor is closed.");
            saveLogToBaDb(strContextCn, strContextEn);
        }

        if (0 == newDchgJcqState  && 1 == m_usOldDchgJcqState)
        {
            strContextCn = "放电接触器断开.";
            strContextEn = QString("Discharge contactor is opened.");
            saveLogToBaDb(strContextCn, strContextEn);
        }
        m_usOldDchgJcqState = newDchgJcqState;
    }
}

//读取DI1--DI6的状态并判断消防告警
int DryCtrlThread::readDevDIState(CBattStack *pStack, quint16 &connFailedCount)
{
    bool  bHasEmerStopStrategy = false;
    bool  bHasWaterStrategy = false;

    if (0 == m_pIOReader->readDevDIState(0,KgGlobalData::ms_dryData))//查询成功
    {
        if (KgGlobalData::ms_dryData.readDiCount < 100)
        {
            KgGlobalData::ms_dryData.readDiCount += 1;
        }
        /* deleted 2022-12-31
#ifdef ND_VER_PROGRAM   // 南都版本, 水浸由消防改变而来 2021-11-30  改xnview_zh.qm
        if (999 == pStack->usWaterBankAddr)// 电池组地址 0 - 未配置 999 - 接BA  水浸接DI4     紧急停机
		{
			bHasEmerStopStrategy = true;
		}
#else
		if (200 == pStack->usEmerStopStrategy)
		{
			bHasEmerStopStrategy = true;
		}
		
	    if (999 == pStack->usWaterBankAddr)// 电池组地址 0 - 未配置 999 - 接BA  水浸接DI4
	    {
      	    bHasWaterStrategy = true;
	    }
#endif
*/
        //KgGlobalData::ms_dryData.bReadDiFlag = true;
        //printf("get DI1-6 state:%d\n", g_DIState);
        //处理读取到的DI信息 begin
        //printf("pStack->usFireBankAddr======================%d\n", pStack->usFireBankAddr);
        //if (999 == pStack->usFireBankAddr) // 999 - 接BA  消防接DI3 modified 2021-12-7
        {
            judgeXfAlarm();
            judgeXfSparyAlam();
            judgeXfFaultAlam();

            judgeXfAutoManu();
            judgeElecPowerOff();

            judgeCombusGasAlarm();
        }

        //if (bHasWaterStrategy)
        {
            judgeWaterAlarm();
            judgeWaterAlarmSec();
        }

        judgeThunderAlarm();
        judgeThunderAlarmSec();
        judgeFuseAlarm();
        judgeXfMotionMsg();
        judgeXfWarmMsg();
        judgeUpsAlarm();
        judgeDoorAlarm();
        judgeDoorAlarmSec();
        judgeAcFault();
        judgeLqFault();

        judgetResState();

        //if (bHasEmerStopStrategy)
        //{
        judgeEmergeStop();
        judgeEmergeStopSec();
        //}

        judgetConfSwitchState(KgGlobalData::ms_pStack);
        judgeIsolSwitchAggrState();
        judgeMainSwitchState();
        judgeChgJcqState();

        judgeBmsLocalState();
        judgeBmsRemoteState();

        // HZ alarm // added 2023-12-21
        if (KgGlobalData::ms_waterStrategy.diList.size() + KgGlobalData::ms_waterStrategySec.diList.size() > 0 ||
            has485WaterAlarm(1))
        {
            if (m_waterAlarm + m_waterAlarmSec + has485WaterAlarm(2) > 0)
                KgGlobalData::ms_pStack->aWaterAlarm = 1;
            else
                KgGlobalData::ms_pStack->aWaterAlarm = 0;
        }

        if (KgGlobalData::ms_emgStopStrategy.diList.size() + KgGlobalData::ms_emgStopStrategySec.diList.size() >0)
        {
            if (m_emergStopAlarm + m_emergStopAlarmSec > 0)// 发生急停
            {
                KgGlobalData::ms_pStack->usEmerStopState = 1;
                KgGlobalData::ms_pStack->aEmerStop = 1;
                writeKgLogfile(QString("step3 EmerStopState pStack->usEmerStopState=%1").arg(KgGlobalData::ms_pStack->usEmerStopState));
            }
            else
            {
                KgGlobalData::ms_pStack->usEmerStopState = 2;
                KgGlobalData::ms_pStack->aEmerStop = 0;
                writeKgLogfile(QString("step4 EmerStopState pStack->usEmerStopState=%1").arg(KgGlobalData::ms_pStack->usEmerStopState));
            }
        }

        if (g_runCount < 100)
            g_runCount += 1;
        //处理读取到的DI信息 end
    }

    return 0; // added 2023-11-9
}

quint16 DryCtrlThread::getConfSwitchState(CBattStack *pStack, DI_STU diStu)
{
    quint16 state = 0; // 记录汇流开关是否闭合

    //if (KgGlobalData::ms_hlkgStrategy.diCfg.diIndex < m_devDoCount)
    //{
    //int hlkgMask = 1 << KgGlobalData::ms_hlkgStrategy.diCfg.diIndex;
    int hlkgMask = 1 << diStu.diIndex;
    if (1 == diStu.alarmValue) // 检查到值为1（干结点闭合)表示汇流开关闭合  常用配置 modified 2021-06-22
    {
        if (hlkgMask == (hlkgMask & KgGlobalData::ms_dryData.DIVal))   //DI1值为1，汇流开关闭合
        {
            state = 1;//汇流开关已经闭合
        }
    }
    else // 检查到值为0（干结点断开)表示汇流开关闭合
    {
        if (hlkgMask != (hlkgMask & KgGlobalData::ms_dryData.DIVal))   //DI1值为0，汇流开关闭合
        {
            state = 1;//汇流开关已经闭合
        }
    }
    //}

    return state;
}

quint16 DryCtrlThread::getClosedConfSwitchCount()
{
    int closeCount = 0;

    for (int k = 0; k < KgGlobalData::ms_hlkgStrategy.diCfgList.size(); ++k)
    {
        DI_STU diStu = KgGlobalData::ms_hlkgStrategy.diCfgList[k];
        if (getConfSwitchState(KgGlobalData::ms_pStack,diStu) > 0)
        {
            closeCount += 1;
        }
    }

    return closeCount;
}

QString DryCtrlThread::getConfSwitchStrState()
{
    QString strState;

    for (int k = 0; k < KgGlobalData::ms_hlkgStrategy.diCfgList.size(); ++k)
    {
        if (k > 0)
        {
            strState += QString("-");
        }
        strState += QString("%1").arg(m_hlkgState[k]);
    }

    return strState;
}


//跳机时驱动分闸
quint16 DryCtrlThread::waitFzOpt(quint16 ctrlType, quint16 &drvFzCount, quint16 &drvFzSuccedCount, QDateTime &drvFzTime, QDateTime statChangeTime)
{
    QString strContextCn = "";
    QString strContextEn = "";
    QString strLog;
    quint16 usDrvFz = 0;

    if (0 == drvFzCount)// 还没有发送分闸命令 // 第一次一定会下发，不管是否已经分闸
    {
        if (!statChangeTime.isValid())
        {
            statChangeTime = QDateTime::currentDateTime();
        }
        /*
   	    if (getHlKgState(pStack) == 0)//DI1为0, 电操已分闸 2020-2-22 added
   	    {
   	         QDateTime nowTime = QDateTime::currentDateTime();
	   	     int elapseSec  = drvFzTime.secsTo(nowTime);
			 if (drvFzTime.isValid() && elapseSec < 120)//120秒内不重复执行
			 {
				 strLog = QString("drvFzCount:%1, waitFzOpt=====================================has FZ OK").arg(drvFzCount);
			     sendLog(0, strLog);
			     return 0;
			 }
   	    }
		*/

        int cirCount = 0;
        while(1) // 延时处理：在断开接触器之前4秒，先控制汇流开关分闸
        {
            if (++cirCount >= 3000)// 等待30秒还没有发送分闸命令，出错
            {
                strLog = QString("Try drive FZ failed**********.");
                sendLog(0, strLog);
                break;
            }
            if ((cirCount%100) == 0)
            {
                strLog = QString("WaitFzOpt ======== usDelayBeforeCutCntor:%1, wait time:%2S.")
                .arg(KgGlobalData::ms_pStack->usDelayBeforeCutCntor).arg(cirCount*10/1000.0);
                sendLog(0, strLog);
            }

            QDateTime nowTime = QDateTime::currentDateTime();
            qint64 elapseSec = statChangeTime.msecsTo(nowTime);

            //QString strInfo = statChangeTime.toString("hh:mm:ss   ") + nowDateTime.toString("hh:mm:ss");
            //sendLog(0, strInfo);

            int waitTime = 0;
            if (KgGlobalData::ms_pStack->usDelayBeforeCutCntor > 4)
            {
                waitTime = KgGlobalData::ms_pStack->usDelayBeforeCutCntor-4;
            }

            if (elapseSec >= waitTime*1000)//故障发生超过Delay秒
            {
                drvFzCount += 1;
                usDrvFz = 1;//驱动分闸
                strLog = QString("WaitFzOpt ======== FZ, drvFzCount:%1.").arg(drvFzCount);
                sendLog(0, strLog);

                if (1 == ctrlType)
                {
                    //saveLogToBaDb(kgConvert("控制汇流开关分闸."));
                }
                else
                {
                    //saveLogToBaDb(kgConvert("EMS控制汇流开关分闸."));
                }
                strContextCn = QString("控制汇流开关分闸");
                strContextEn = QString("Control opening bus switch.");
                saveLogToBaDb(strContextCn, strContextEn);
                drvFzTime = nowTime;
                break;
            }
            this->msleep(10);
        }
    }
    else//已发送分闸命令
    {
        if (!drvFzTime.isValid())
        {
            drvFzTime = QDateTime::currentDateTime();
        }
        //if (getHlKgState(KgGlobalData::ms_pStack) > 0)// DI1为1,电操还没断开
        if (getClosedConfSwitchCount() > 0) // 电操还没断开
        {
            if (1 == drvFzSuccedCount) // 前面已经分闸，现在刚又检测到合闸
            {
                if (1 == ctrlType)
                {
                    //saveLogToBaDb(kgConvert("控制汇流开关分闸."));
                }
                else
                {
                    //saveLogToBaDb(kgConvert("EMS控制汇流开关分闸."));
                }
                strContextCn = QString("控制汇流开关分闸");
                strContextEn = QString("Control bus switch opening.");
                saveLogToBaDb(strContextCn, strContextEn);
            }
            drvFzSuccedCount = 0;
            //if (drvFzCount < 3)//最多只试3次 modified 2021-9-19
            //{
            QDateTime nowTime = QDateTime::currentDateTime();
            int elapseSec  = drvFzTime.secsTo(nowTime);
            strLog = QString("waitFzOpt================elapseSec:%1").arg(elapseSec);
            sendLog(0, strLog);

            if (elapseSec >= 2)//至少过2秒还没有响应，重新发送命令 //10  modified 2021-9-19
            {
                if (++drvFzCount >= 30000)
                {
                    drvFzCount = 20000;
                }

                if (drvFzCount < 150)  // 分闸不成功时，前5分钟每2秒操作一次
                {
                    usDrvFz = 1;//驱动分闸
                }
                else
                {
                    if (150 == drvFzCount)
                    {
                        strContextCn = QString("控制汇流开关分闸失败");
                        strContextEn = QString("Control opening bus switch failed.");
                        saveLogToBaDb(strContextCn, strContextEn);
                    }
                    if ((drvFzCount%8) == 0)// 分闸不成功时，5分钟后每16秒操作一次
                    {
                        usDrvFz = 1;//驱动分闸
                    }
                }

                strLog = QString("waitFzOpt================FZ, try drive FZ again, drvFzCount:%1, fzSuccedCount:%2.").arg(drvFzCount).arg(drvFzSuccedCount);
                sendLog(0, strLog);
                drvFzTime = nowTime;
            }
            //}
            //else//分闸失败
            //{
            //	 strLog = QString("WaitFzOpt ********** FZ failed.");
            //   sendLog(0, strLog);
            //}
        }
        else//已经分闸
        {
            strLog = QString("WaitFzOpt ======== has FZ OK, drvFzCount:%1, fzSuccedCount:%2.").arg(drvFzCount).arg(drvFzSuccedCount);
            sendLog(0, strLog);

            /*
		    uchar index = 0;
			bool  bHasEmerStopStrategy = false;
			bool  bHasWaterStrategy = false;
			
			m_pDataBuf[index++] = 0x99;
			m_pDataBuf[index++] = 06;  

			int regAddr = 0x5000;
			addParam2Buffer(m_pDataBuf+index, regAddr);// 起始地址:要查询的第一个光耦寄存器地址
			index += 2;

			int regVal = 0x1234;
			addParam2Buffer(m_pDataBuf+index, KgGlobalData::ms_devDiCount);// 寄存器个数:要查询的光耦寄存器数量
			index += 2;

			quint16 crcValue = Modbus_CRC16((uchar*)m_pDataBuf, index);
			addParam2Buffer(m_pDataBuf+index, crcValue);
			index += 2;

			int  nByte = m_pRtuClient->writeBlock((unsigned char*)m_pDataBuf, index);
			*/

            drvFzCount = 1;

            if (drvFzSuccedCount < 2) // 执行成功后再操作分闸2次
            {
                drvFzSuccedCount += 1;
                usDrvFz = 1;//驱动分闸
                drvFzTime = QDateTime::currentDateTime();
            }
        }
    }

    return usDrvFz;
}

//驱动合闸
quint16 DryCtrlThread::waitHzOpt(quint16 ctrlType, quint16 &drvHzCount, QDateTime &drvHzTime)
{
    QString strContextCn = "";
    QString strContextEn = "";
    QString strLog;
    quint16 usDrvHz = 0;

    if (0 == drvHzCount)//还没有发送合闸命令
    {
        //控制第1个DO口闭合
        drvHzCount += 1;
        usDrvHz = 1;//驱动合闸
        sendLog(0, QString("WaitHzOpt ======== HZ, drvHzCount:%1.").arg(drvHzCount));

        if (1 == ctrlType)
        {
            //saveLogToBaDb(kgConvert("控制汇流开关合闸."));
        }
        else
        {
            //saveLogToBaDb(kgConvert("EMS控制汇流开关合闸."));
        }
        strContextCn = QString("控制汇流开关合闸");
        strContextEn = QString("Control bus switch closing.");
        saveLogToBaDb(strContextCn, strContextEn);
        drvHzTime = QDateTime::currentDateTime();
    }
    else//已发送合闸命令
    {
        //if (getHlKgState(KgGlobalData::ms_pStack) > 0)//DI1为1,电操已经合上 2020-2-22 added
        if (getClosedConfSwitchCount() < KgGlobalData::ms_hlkgStrategy.diCfgList.size())
        {
            QDateTime nowTime = QDateTime::currentDateTime();
            int elapseSec  = drvHzTime.secsTo(nowTime);
            if (drvHzTime.isValid() && elapseSec < 120)//120秒内不重复执行
            {
                sendLog(0, QString("WaitHzOpt ======== has HZ OK, drvHzCount:%1.").arg(drvHzCount));
                return 0;
            }
        }

        //if (getHlKgState(KgGlobalData::ms_pStack) == 0)//DI1为0, 电操还没合上
        if (getClosedConfSwitchCount() < KgGlobalData::ms_hlkgStrategy.diCfgList.size())
        {
            //if (drvHzCount < 3)//最多只试3次 modified 2021-9-19
            //{
            QDateTime nowDateTime = QDateTime::currentDateTime();
            int elapseSec  = drvHzTime.secsTo(nowDateTime);
            strLog = QString("waitHzOpt================elapseSec:%1").arg(elapseSec);
            sendLog(0, strLog);

            if (elapseSec >= 5)//至少过5秒还没有响应，重新发送命令// 10  modified 2021-9-19
            {
                drvHzCount += 1;
                usDrvHz = 1;//驱动合闸
                strLog = QString("waitHzOpt================HZ, try drive HZ again, drvHzCount:%1").arg(drvHzCount);
                sendLog(0, strLog);
                drvHzTime = nowDateTime;
            }
            //}
            //else //合闸失败
            //{
            //   //pStack->usStackTemp[27] = 0;
            //   KgGlobalData::ms_pStack->usStackTemp[12] = 0;
            //   strLog = QString("waitHzOpt ********** HZ failed");
            //   sendLog(0, strLog);
            //}
        }
        else //已经合闸, 修改合闸总次数，否则如果持续有合闸命令，但DI1突然变为0，则会继续发送合闸命令
        {
            //pStack->usStackTemp[27] = 0;
            KgGlobalData::ms_pStack->usStackTemp[12] = 0;
        }
    }

    return usDrvHz;
}

void DryCtrlThread::parseStackState(quint16 stackState, quint16 &usHasProt, quint16 &usHasAlarm,
                                    quint16 &usChargeFull, quint16 &usDischargeEmpty, quint16 &usProhibitChgDchg)
{
    usHasProt = 0; 
    usHasAlarm = 0;
    usChargeFull = 0;
    usDischargeEmpty = 0;
    usProhibitChgDchg = 0;

#ifdef MASTER_VER  // BA通用版本
    if (0xAAAA == stackState)
    {
        usHasProt = 1;
    }
    else if (0x5555 == stackState)
    {
        usHasAlarm = 1;
        usProhibitChgDchg = 1;
    }
    else if (0x1111 == stackState)
    {
        usChargeFull = 1;
        usHasAlarm = 1;
    }
    else if (0x2222 == stackState)
    {
        usDischargeEmpty = 1;
        usHasAlarm = 1;
    }
    else
        ;
#endif

#ifdef ND_VER_PROGRAM 		// 南都版本
    // 电池堆状态     0x1006    0 - 正常   1 - 禁充    2 - 禁放    3 - 待机     4 - 停机
    if (4 == stackState)
    {
        usHasProt = 1;
    }
    else if (3 == stackState)
    {
        usHasAlarm = 1;
        usProhibitChgDchg = 1;
    }
    else if (1 == stackState)
    {
        usChargeFull = 1;
        usHasAlarm = 1;
    }
    else if (2 == stackState)
    {
        usDischargeEmpty = 1;
        usHasAlarm = 1;
    }
    else
        ;
#endif
}

// 如果有断路器断开，则强制为保护告警  //added 2021-5-13
void DryCtrlThread::lszhParseDLQState(quint16 &usHasProt)
{
    //if (1 == g_bReadDiFlag)//if (KgGlobalData::ms_dryData.bReadDiFlag)
    if (KgGlobalData::ms_dryData.readDiCount > 0)
    {
        if ((0x0F & KgGlobalData::ms_dryData.DIVal) == 0x0) // 4个断路器都没有脱扣
        {
        }
        else // 有断路器脱扣
        {
            usHasProt = 1;
        }
    }
}

int isSystemError(int stackState)
{
    int isError = 0;

#ifdef MASTER_VER  // BA通用版本
    if (0xAAAA == stackState)
    {
        isError = 1;
    }
#endif

#ifdef ND_VER_PROGRAM 		// 南都版本
    if (4 == stackState)
    {
        isError = 1;
    }
#endif
    return isError;
}

// added 2022-6-30
bool hasSomeProt()
{
    bool iHasProt = false;

    for (int k = 0; k < KgGlobalData::ms_installBankNum; ++k)
    {
        CBattBank *pBank = KgGlobalData::ms_pRTDB->getBank(k);

        if (pBank && isBankInStack(k))
        {
            // 放电温度上限保护   单体电压下限保护   组电压下限保护
            if (pBank->aDchgTempUpLimitProt || pBank->aSglVolDownLimitProt || pBank->aBankVolDownLimitProt)
            {
                iHasProt = true;
                break;
            }
        }
    }

    return iHasProt;
}

// 判断是否有合闸命令 added 2022-1-25
int hasEmsHzCmd(CBattStack *pStack)
{
    bool retResult = false;

#ifdef MASTER_VER  // BA通用版本
    if (1 == pStack->usEMSConfCtrl)
    {
        retResult = true;
    }
#endif

    return retResult;
}

// 判断是否有分闸命令
int hasEmsFzCmd(CBattStack *pStack)
{
    bool retResult = false;

#ifdef MASTER_VER  // BA通用版本
    if (2 == pStack->usEMSConfCtrl)
    {
        retResult = true;
    }
#endif

    return retResult;
}

void clearEmsCmd(CBattStack *pStack)
{
#ifdef MASTER_VER  // BA通用版本
    pStack->usEMSConfCtrl = 0;
#endif
}

quint16 DryCtrlThread::hasEmertStopAlarm()
{
    quint16 retResult = 0;
#ifdef MASTER_VER  // BA通用版本
    // 紧急停机状态             0 - 默认  1 - 告警  2 - 正常
    // modified 2022-05-27
    //if (1 == KgGlobalData::ms_pStack->usEmerStopState || m_emergStopAlarm > 0)
    if ((m_emergStopAlarm + m_emergStopAlarmSec) > 0)
    {
        retResult = 1;
    }
#else
    if (m_emergStopAlarm > 0)
    {
        retResult = 1;
    }
#endif

    return retResult;// m_emergStopAlarm;
}

quint16  DryCtrlThread::hasFireAlarm()
{
    return m_fireAlarm;
}

quint16 DryCtrlThread::hasWaterAlarm() // added 2024-11-7
{
    quint16 retResult = 0;

    if (m_waterAlarm + m_waterAlarmSec + has485WaterAlarm(2) > 0)
    {
        retResult = 1;
    }

    return retResult;
}

bool DryCtrlThread::isRemoteMode() // added 2024-5-4
{
    bool isRemote = true; // 默认为远程模式

    //if (0 == m_bmsLocalState &&  1 == m_bmsRemoteState)
    //{
    //}

    // 远方模式时，才接收合闸命令 // added 2024-5-4
    if (KgGlobalData::ms_bmsLocalStrategy.diList.size() > 0 && m_bmsLocalState > 0)
    {
        isRemote = false;
    }

    if (KgGlobalData::ms_bmsRemmoteStrategy.diList.size() > 0 && 0 == m_bmsRemoteState)
    {
        isRemote = false;
    }

    return isRemote;
}

int g_oldHlkgHzCount = 0;
bool DryCtrlThread::controlHzFz()
{    
    QString strContextCn = "";
    QString strContextEn = "";
    quint16   usDrvFz = 0;    //是否驱动分闸
    quint16   usDrvHz = 0;    //是否驱动合闸
    QString strHint;
    int doIndex = 0;
    int k;

    CBattStack *pStack = KgGlobalData::ms_pStack;

    // step3. 判断是否需要分闸合闸操作
    //quint16   usDrvFz = 0;    //是否驱动分闸
    //quint16   usDrvHz = 0;    //是否驱动合闸
    int needBreakCnt = NeedBreakJCQCount();
    int needCloseCnt = NeedCloseJCQCount();
    int closedCnt = GetClosedJCQCount();
    int openedCnt = GetOpenedJCQCount();
    // 平高昆山usStackTemp[27], 许继江虹变usStackTemp[12] 27
    // quint16 emsCtrlHz = pStack->usStackTemp[27];//EMS控制的合闸分闸信号
    // pStack->usStackTemp[27] = 0;

    quint16 emsCtrlHz  = 0;
    quint16 tmpCmd  = 0;
    quint16 hasUsed = 0;

#ifdef ND_HNXJ	// added 2022-10-12
    hasUsed = true; // usStackTemp[27]已被使用
#endif

#ifdef HJ_5MWH	
    hasUsed = true; // usStackTemp[27]已被使用
#endif

    if (!hasUsed)
    {
        if (isRemoteMode())// 远方模式时，才接收命令 // added 2024-5-4
        {
            tmpCmd = pStack->usStackTemp[27];//EMS控制的合闸分闸信号, 1-上电, 2-下电
            pStack->usStackTemp[27] = 0;
        }
    }

#ifdef ND_VER_PROGRAM	
    if (1 == tmpCmd)     // 上电命令
    {
        // 并网连接状态  1 - 启动(Start Connection);  2 - 成功(Connection Successful);  3 - 结束(Process End)；
        if (2 == pStack->usConnState)  //  并网后才接收上电命令
        {
            emsCtrlHz = 1;
        }
        else
        {
            strHint = QString("***********************ND Ver, usConnState:%1, refuse to connect.").arg(pStack->usConnState);
            sendLog(0, strHint);
        }
    }
    else if (2 == tmpCmd)// 下电命令
    {
        emsCtrlHz = 2;
    }
    else
        ;
    if (m_oldConnState != pStack->usConnState)
    {
        m_drvHzCount = 0;
    }
    m_oldConnState = pStack->usConnState;
    strHint = QString("***********************ND Ver data, usConnState:%1, emsCtrlHz:%2.").arg(pStack->usConnState).arg(emsCtrlHz);
    sendLog(0, strHint);
#else
    emsCtrlHz = tmpCmd;
    strHint = QString("=============emsCtrlHz:%1, usEMSContCtrl:%2, usEMSConfCtrl:%3.")
                  .arg(emsCtrlHz).arg(pStack->usEMSContCtrl).arg(pStack->usEMSConfCtrl);  // 堆接触器管理  // 汇流开关管理
    sendLog(0, strHint);
#endif
    strHint = QString("NeedBreakCnt:%1, needCloseCnt:%2, closedCnt:%3, openedCnt:%4, emsCtrlHz:%5.")
                  .arg(needBreakCnt).arg(needCloseCnt).arg(closedCnt).arg(openedCnt).arg(emsCtrlHz);
    sendLog(0, strHint);

    if (isSystemError(m_stackState))
    {
        g_masterHZCmd = 0;
    }

    // 1.BA故障时主动分闸  ************************************************
    if (KgGlobalData::ms_hlkgStrategy.fzDoList.size() > 0) // 有分闸干结点
    {
        // 2022-01-09 (1)实现急停和消防时立刻断开汇流开关；(2)断开失败时不断重试分闸;(3)操作成功时再执行一次。
        //if ( 1 == m_fireAlarm || 1 == m_waterAlarm) // 有 急停 或 消防告警
        //if (hasEmertStopAlarm() || 1 == m_fireAlarm || 1 == m_fireSprayAlarm || 1 == m_waterAlarm) // 有 急停 或 消防告警
        char xfWarnFz = 0;
        char xfAlarmFz = 0; // added 2024-4-27
        char waterAlarmFz = 0;
        if (KgGlobalData::ms_xfWarnFzEnabled > 0 && 1 == m_xfWarmMsg)
        {
            xfWarnFz = 1;
        }
        if (KgGlobalData::ms_xfAlarmFzEnabled > 0 && 1 == m_fireAlarm)
        {
            xfAlarmFz = 1;
        }
        if (KgGlobalData::ms_waterAlarmFzEnabled > 0 && 1 == m_waterAlarm)
        {
            waterAlarmFz = 1;
        }

        if (hasEmertStopAlarm() || ((xfWarnFz + xfAlarmFz + waterAlarmFz) > 0) || 1 == m_fireSprayAlarm)
        {
            if (1 != m_usOldEmerStopState && hasEmertStopAlarm()) // 刚发生急停，需要立马断开汇流开关，不延时 added 2022-1-6
            {
                if (getClosedConfSwitchCount() > 0)
                {
                    strContextCn = QString("急停,分闸汇流开关");
                    strContextEn = QString("Emergency, open bus switch.");
                    saveLogToBaDb(strContextCn, strContextEn);
                }
                m_drvFzCount = 1;
                m_drvFzSuccedCount = 0;
                usDrvFz = 1;
                m_drvFzTime = QDateTime::currentDateTime();
                if (0 == getClosedConfSwitchCount())
                {
                    //m_drvFzSuccedCount = 1;
                }
            }
            else if (0 == m_oldFireAlarm && 1 == m_fireAlarm)      // 刚发生消防，需要立马断开汇流开关，不延时 added 2022-1-6
            {
                if (getClosedConfSwitchCount() > 0)
                {
                    strContextCn = QString("消防告警,分闸汇流开关.");
                    strContextEn = QString("Fire alarm, open bus switch.");
                    saveLogToBaDb(strContextCn, strContextEn);
                }
                m_drvFzCount = 1;
                m_drvFzSuccedCount = 0;
                usDrvFz = 1;
                m_drvFzTime = QDateTime::currentDateTime();
                if (0 == getClosedConfSwitchCount())
                {
                    //m_drvFzSuccedCount = 1;
                }
            }
            else if (0 == m_oldFireSprayAlarm && 1 == m_fireSprayAlarm)      // 刚发生消防，需要立马断开汇流开关，不延时 added 2022-1-6
            {
                if (getClosedConfSwitchCount() > 0)
                {
                    strContextCn = QString("消防喷洒,分闸汇流开关.");
                    strContextEn = QString("Fire spray, open bus switch.");
                    saveLogToBaDb(strContextCn, strContextEn);
                }
                m_drvFzCount = 1;
                m_drvFzSuccedCount = 0;
                usDrvFz = 1;
                m_drvFzTime = QDateTime::currentDateTime();
                if (0 == getClosedConfSwitchCount())
                {
                    //m_drvFzSuccedCount = 1;
                }
            }
            else
            {
                /*
				if (0 == g_oldHlkgHzCount && getClosedConfSwitchCount() > 0) // 汇流开关还合上
				{
					m_drvFzCount = 1;
					usDrvFz = 1;
					saveLogToBaDb(kgConvert("检测到汇流开关合闸,强制分闸."));
				}*/
                usDrvFz = waitFzOpt(1, m_drvFzCount, m_drvFzSuccedCount, m_drvFzTime, m_statChangeTime);
            }
        }
        else if (isSystemError(m_stackState) &&  needBreakCnt > 0)// BA故障，消防和急停时，驱动分闸
        {
            usDrvFz = waitFzOpt(1, m_drvFzCount, m_drvFzSuccedCount, m_drvFzTime, m_statChangeTime);
        }
#ifdef  YW0357_PRJ
        else if ((0x5555 == pStack->usStackState || 0x2222 == pStack->usStackState) &&
                 hasSomeProt())// BA禁放，放电温度上限保护 或 单体电压下限保护时，驱动分闸   // added 2022-6-30
        {
            usDrvFz = waitFzOpt(1, m_drvFzCount, m_drvFzSuccedCount, m_drvFzTime, m_statChangeTime);
        }
#endif
        /*else if (1 == m_fireAlarm || 1 == m_emergStopAlarm) // 再判断一下会更好，保证消防和急停时会驱动分闸 added 2021-9-19
		{
			m_statChangeTime = QDateTime::currentDateTime();
			usDrvFz = waitFzOpt(m_drvFzCount, m_drvFzSuccedCount, m_drvFzTime, m_statChangeTime);
		}
		*/
        else
            ;
        m_usOldEmerStopState = hasEmertStopAlarm();
        m_oldFireAlarm = m_fireAlarm;
        m_oldFireSprayAlarm = m_fireSprayAlarm;
    }

    g_oldHlkgHzCount = getClosedConfSwitchCount();

    // 2.检测异常情况，有必要时主动分闸  ************************************************
    // added 2020-5-21 检测接触器断开,但汇流开关合闸状态，如有过30秒主动分闸
    if (0 == usDrvFz && 0 == usDrvHz && KgGlobalData::ms_hlkgStrategy.fzDoList.size() > 0) // 当前没有驱动合闸分闸
    {
        //if (openedCnt > 0 && (getHlKgState(pStack) > 0))// 有接触器断开，汇流开关还处于合闸状态
        if (openedCnt > 0 && (getClosedConfSwitchCount() > 0))
        {
            m_detectYcCount += 3; // 先计时
            sendLog(0, QString("Step501 detectYcCount:%1.").arg(m_detectYcCount));
        }
        else // 数据清0
        {
            m_detectYcCount = 0;
            m_masterFzCount = 0;
            sendLog(0, QString("Step502 clear detectYcCount."));
        }

        if (m_detectYcCount >= 30*4) // 维持30秒后，主动进行分闸
        {
            if (m_masterFzCount < 1) // 只下发1次
            {
                usDrvFz = 1;
                m_masterFzCount += 1;
                sendLog(0, QString("***Master FZ."));
                strContextCn = QString("接触器已断开,强制分闸汇流开关.");
                strContextEn = QString("Contactor has been opened, opening bus switch.");
                saveLogToBaDb(strContextCn, strContextEn);
            }
        }
    }

    // 3.配置为自动合闸时，接触器都闭合后主动合闸  ************************************************
    if (1== KgGlobalData::ms_hzEnabled && 0 == usDrvFz && 0 == usDrvHz &&
        KgGlobalData::ms_hlkgStrategy.hzDoList.size() > 0 && KgGlobalData::ms_bankNumInStack > 0) // 当前没有驱动合闸分闸
    {
        if (0 == m_fireAlarm && 0 == hasEmertStopAlarm())
        {
            // 所有电池组接触器都闭合, 汇流开关还处于分闸状态
            // if (closedCnt >= KgGlobalData::ms_bankNumInStack && (getHlKgState(pStack) == 0))
            // added 2024-5-4 added (0 == m_bmsLocalState &&  1 == m_bmsRemoteState)
            if (!isSystemError(m_stackState) && isRemoteMode() &&
                closedCnt >= KgGlobalData::ms_bankNumInStack && (getClosedConfSwitchCount() < KgGlobalData::ms_hlkgStrategy.diCfgList.size()))
            {
                m_detectOkCount += 3; // 先计时
                sendLog(0, QString("Step503 detectOkCount:%1.").arg(m_detectOkCount));
            }
            // added 2024-4-26 修改没有汇流开关反馈节点时，也可以自动控制合闸
            else if (!isSystemError(m_stackState) && isRemoteMode() &&
                     closedCnt >= KgGlobalData::ms_bankNumInStack && (0 == g_masterHZCmd && 0 == KgGlobalData::ms_hlkgStrategy.diCfgList.size()))
            {
                m_detectOkCount += 3; // 先计时
                sendLog(0, QString("Step503 detectOkCount:%1.").arg(m_detectOkCount));
            }
            else // 数据清0
            {
                m_detectOkCount = 0;
                m_masterHzCount = 0;
                sendLog(0, QString("Step504 clear detectOkCount."));
            }

            //if (m_detectOkCount >= 15) // 维持15秒后，主动进行合闸
            //if (m_detectOkCount >= 30) // 维持15秒后，主动进行合闸
            if (m_detectOkCount >= 90) // 维持15秒后，主动进行合闸
            {
                m_detectOkCount = 0;

                if (m_masterHzCount < 3) // 只下发3次
                {
                    g_masterHZCmd = 1;
                    usDrvHz = 1;
                    m_masterHzCount += 1;
                    sendLog(0, QString("***Master HZ."));
                    if (1 == m_masterHzCount)
                    {
                        strContextCn = QString("接触器已闭合,强制合闸汇流开关.");
                        strContextEn = QString("Contactor has been closed, closing bus switch.");
                        saveLogToBaDb(strContextCn, strContextEn);
                    }
                }
            }

            /*if (detectOkCount >= 30) // 维持30秒后，再主动进行合闸
			{
			   if (masterHzCount < 2) // 只下发1次
				{
					usDrvHz = 1;
					masterHzCount += 1;
					sendLog(0, QString("try master HZ again"));
				}
			}*/
        }
    }
    //added end

    // 4.接受EMS的合闸分闸命令  ************************************************
    if (0 == usDrvFz && 0 == usDrvHz) // 当前没有驱动合闸分闸
    {
        if (1 == emsCtrlHz || hasEmsHzCmd(pStack)) //驱动合闸 // || 1 == pStack->usEMSConfCtrl
        {
            if (hasEmsHzCmd(pStack))//if (1 == pStack->usEMSConfCtrl) // added 2022-1-19
            {
                clearEmsCmd(pStack);//  pStack->usEMSConfCtrl = 0;
            }

            for (int k = 0; k < 10; ++k)
            {
                sendLog(0, QString("============================================1Recv HZ cmd from EMS."));
            }

            if (!isSystemError(m_stackState) && closedCnt >= KgGlobalData::ms_bankNumInStack) // 无故障，且所有电池组接触器都闭合
            {
                //sendLog(0, QString("=====Recv HZ cmd from EMS."));
                for (int k = 0; k < 10; ++k)
                {
                    sendLog(0, QString("============================================2Recv HZ cmd from EMS."));
                }
                usDrvHz = 1;//驱动合闸
                //usDrvHz = waitHzOpt(2, m_drvHzCount, m_drvHzTime);

                if (m_saveEmsCtrlHzRdCount < 5)
                {
                    m_saveEmsCtrlHzRdCount += 1;
                    if (1 == emsCtrlHz)
                    {
                        strContextCn = QString("远程控制合闸.");
                        strContextEn = QString("Remote closing bus switch.");
                        saveLogToBaDb(strContextCn, strContextEn);
                    }
                    else
                    {
                        strContextCn = QString("远程控制合闸(BMS控制).");
                        strContextEn = QString("Remote closing bus switch(BMS control).");
                        saveLogToBaDb(strContextCn, strContextEn);
                    }
                }
            }
            else  // 有电池组接触器没有闭合，拒绝合闸命令
            {
                sendLog(0, QString("=====Reject HZ cmd from EMS."));
                if (m_saveRejectEmsHzRdCount < 5)
                {
                    m_saveRejectEmsHzRdCount += 1;
                    if (1 == emsCtrlHz)
                    {
                        strContextCn = QString("条件不具备，拒绝远程合闸.");
                        strContextEn = QString("Reject remote closing bus switch.");
                        saveLogToBaDb(strContextCn, strContextEn);
                    }
                    else
                    {
                        strContextCn = QString("条件不具备，拒绝远程合闸(BMS控制).");
                        strContextEn = QString("Reject remote closing bus switch(BMS control).");
                        saveLogToBaDb(strContextCn, strContextEn);
                    }
                }
            }
        }
        else if (2 == emsCtrlHz || hasEmsFzCmd(pStack))//驱动分闸 // || 2 == pStack->usEMSConfCtrl
        {
            //sendLog(0, QString("=====Recv FZ cmd from EMS."));
            if (hasEmsFzCmd(pStack))//if (2 == pStack->usEMSConfCtrl) // added 2022-1-19
            {
                clearEmsCmd(pStack);//   pStack->usEMSConfCtrl = 0;
            }

            for (int k = 0; k < 10; ++k)
            {
                sendLog(0, QString("=================================================Recv FZ cmd from EMS."));
            }
            usDrvFz = 1;//驱动分闸
            //usDrvFz = waitFzOpt(2, m_drvFzCount, m_drvFzSuccedCount, m_drvFzTime, m_statChangeTime);

            if (m_saveEmsCtrlFzRdCount < 5)
            {
                m_saveEmsCtrlFzRdCount += 1;
                if (2 == emsCtrlHz)
                {
                    strContextCn = QString("远程控制分闸.");
                    strContextEn = QString("Remote opening bus switch.");
                    saveLogToBaDb(strContextCn, strContextEn);
                }
                else
                {
                    strContextCn = QString("远程控制分闸(BMS控制).");
                    strContextEn = QString("Remote opening bus switch(BMS control).");
                    saveLogToBaDb(strContextCn, strContextEn);
                }
            }
        }
        else
            ;
    }

    // step4.下发控制DO1--DO6干结点命令
    bool bSendCmd = sendHzFzCmd(usDrvHz, usDrvFz);
    return bSendCmd;
}

bool DryCtrlThread::sendHzFzCmd(quint16  usDrvHz, quint16  usDrvFz)
{
    bool bSendCmd = false;
    int k;
    int doIndex;

    //发送合闸命令DO1
    //setDoStateHZ(KgGlobalData::ms_hlkgStrategy.hzDoIndex, usDrvHz);	
    if (KgGlobalData::ms_hlkgStrategy.hzDoList.size() > 0)
    {
        if (usDrvHz) // 需要合闸*************************
        {
            /*
			g_DOState |= (1 << KgGlobalData::ms_hlkgStrategy.hzDoIndex);
			setDevAllDoState();
			
			int delayTime = KgGlobalData::ms_tkDelayTime * 1000;
	        this->msleep(delayTime);//延时300ms
			g_DOState &= ~(1 << KgGlobalData::ms_hlkgStrategy.hzDoIndex);
			setDevAllDoState();
			*/

            openDos(KgGlobalData::ms_dryData.IOCtrl, KgGlobalData::ms_hlkgStrategy.hzDoList);// 先闭合
            //for (k = 0; k < KgGlobalData::ms_hlkgStrategy.hzDoList.size(); ++k)
            //{
            //doIndex = KgGlobalData::ms_hlkgStrategy.hzDoList[k];
            //KgGlobalData::ms_dryData.IOCtrl |= (1 << doIndex);
            //}
            int delayTime = KgGlobalData::ms_tkDelayTime * 1000;
            m_pIOReader->AddSetCmd(0,KgGlobalData::ms_dryData.IOCtrl,delayTime);

            closeDos(KgGlobalData::ms_dryData.IOCtrl, KgGlobalData::ms_hlkgStrategy.hzDoList);// 再断开
            //for (k = 0; k < KgGlobalData::ms_hlkgStrategy.hzDoList.size(); ++k)
            //{
            //doIndex = KgGlobalData::ms_hlkgStrategy.hzDoList[k];
            //KgGlobalData::ms_dryData.IOCtrl &= ~(1 << doIndex);
            //}
            m_pIOReader->AddSetCmd(0,KgGlobalData::ms_dryData.IOCtrl,0);
            m_pIOReader->DealwithSetDoCmd(0,KgGlobalData::ms_dryData); // 执行控制分闸命令

            bSendCmd = true;
        }
    }

    //发送分闸命令DO2
    //setDoStateFZ(KgGlobalData::ms_hlkgStrategy.fzDoIndex, usDrvFz);	
    if (KgGlobalData::ms_hlkgStrategy.fzDoList.size() > 0)
    {
        if (usDrvFz)// 需要分闸*************************
        {
            /*
			g_DOState |= (1 << KgGlobalData::ms_hlkgStrategy.fzDoIndex);
			setDevAllDoState();
			
			int delayTime = KgGlobalData::ms_tkDelayTime * 1000;
	        this->msleep(delayTime);//延时300ms
			g_DOState &= ~(1 << KgGlobalData::ms_hlkgStrategy.fzDoIndex);
			setDevAllDoState();
			*/
            openDos(KgGlobalData::ms_dryData.IOCtrl, KgGlobalData::ms_hlkgStrategy.fzDoList);// 先闭合

            /*if (1 == m_fireAlarm || 1 == m_waterAlarm || 1 == m_combusGasAlarm) // 发生了消防告警
			{
				if (m_xfTkMotionCount < 3)
				{
					m_xfTkMotionCount += 1;
				}
				openDos(KgGlobalData::ms_dryData.IOCtrl, KgGlobalData::ms_hlkgStrategy.xfTkDoList);// 先闭合
				if (0 == m_xfTkMotionLogCount)
				{
					m_xfTkMotionLogCount = 1;
					doIndex = KgGlobalData::ms_hlkgStrategy.xfTkDoList.at(0);
					if (isChLang())
					   saveLogToBaDb(kgConvert("消防告警分励脱扣(DO%1).").arg(doIndex+1));
					else
					   saveLogToBaDb(kgConvert("Fire alarm, opening switch(DO%1).").arg(doIndex+1));
				}
			}

	        bool isVolDownProt = hasVolDownPort();
			if (isVolDownProt) // 发生了低电压保护
			{
				if (m_volDownProtTkCount < 3)
				{
					m_volDownProtTkCount += 1;
				}
				openDos(KgGlobalData::ms_dryData.IOCtrl, KgGlobalData::ms_hlkgStrategy.volDownProtFzDoList);// 先闭合
				if (KgGlobalData::ms_hlkgStrategy.volDownProtFzDoList.size() > 0 && 0 == m_volDownProtTkLogCount)// modifed 2022-11-17
				{
					m_volDownProtTkLogCount = 1;
					doIndex = KgGlobalData::ms_hlkgStrategy.volDownProtFzDoList.at(0);
					if (isChLang())
					   saveLogToBaDb(kgConvert("低电压保护分励脱扣(DO%1).").arg(doIndex+1));
					else
					   saveLogToBaDb(kgConvert("Vol down protect, opening switch(DO%1).").arg(doIndex+1));
				}
			}*/

            int delayTime = KgGlobalData::ms_tkDelayTime * 1000; /////////////////////////////////////////
            m_pIOReader->AddSetCmd(0,KgGlobalData::ms_dryData.IOCtrl,delayTime);

            closeDos(KgGlobalData::ms_dryData.IOCtrl, KgGlobalData::ms_hlkgStrategy.fzDoList);// 再断开

            /*if (1 == m_fireAlarm || 1 == m_waterAlarm || 1 == m_combusGasAlarm) // 发生了消防告警
			{
				closeDos(KgGlobalData::ms_dryData.IOCtrl, KgGlobalData::ms_hlkgStrategy.xfTkDoList);// 再断开
			}

			if (isVolDownProt)   // 发生了低电压保护
			{
				closeDos(KgGlobalData::ms_dryData.IOCtrl, KgGlobalData::ms_hlkgStrategy.volDownProtFzDoList);// 再断开
			}*/

            m_pIOReader->AddSetCmd(0,KgGlobalData::ms_dryData.IOCtrl,0);
            m_pIOReader->DealwithSetDoCmd(0,KgGlobalData::ms_dryData); // 执行控制合闸命令

            msleep(300); // 否则分闸干节点两次控制，中间会断开时间太短 // added 2022-11-17

            bSendCmd = true;
        }
    }

    return bSendCmd;
}

void DryCtrlThread::dealwithConnFailed(int runCount)
{
    QString strContextCn = "";
    QString strContextEn = "";
    // added 2021-3-23
    int connAlarmCount = KgGlobalData::ms_connTimeoutCount;
    if (runCount <  30)     // 程序刚启动时，只需要1次通信故障，就通知BA急停
    {
        connAlarmCount = 1;
    }
    /*else if (30 == runCount)// 启动完毕
	{
		// 原来为通迅故障控制BA停机，则需要继续维持,直到通信正常
		if (g_connFailedCount >= 1 && g_connFailedCount < KgGlobalData::ms_connTimeoutCount)
		{
			g_connFailedCount = KgGlobalData::ms_connTimeoutCount;
			printf("****************************\n");
		}
	}*/
    else
        ;
    //added end
    bool bHasEmerStopStrategy = false;

#ifdef	HAS_EMER_STOP_STRATEGY  // added 2021-3-13
    if (200 == KgGlobalData::ms_pStack->usEmerStopStrategy)
    {
        bHasEmerStopStrategy = true;
    }
#else
    if (999 == KgGlobalData::ms_pStack->usWaterBankAddr)// 电池组地址 0 - 未配置 999 - 接BA  水浸接DI4     紧急停机
    {
        bHasEmerStopStrategy = true;
    }
#endif	

    if (KgGlobalData::ms_dryData.failedCount >= connAlarmCount) // 通迅故障
    {
        KgGlobalData::ms_pStack->aExIOModuConnFault = 1;  // added 2022-5-22
        if (0 == m_usConnFailed || 99 == m_usConnFailed) // have not saved connect errer rd
        {
            m_usConnFailed = 1;            
            strContextCn = QString("串口继电器通信故障.");
            strContextEn = QString("serial trigger communicate fault.");
            saveLogToBaDb(strContextCn, strContextEn);
        }
    }
    else if (0 == KgGlobalData::ms_dryData.failedCount)// 通迅正常
    {
        KgGlobalData::ms_pStack->aExIOModuConnFault = 0;
        if (1 == m_usConnFailed || 99 == m_usConnFailed) // have not saved connect OK rd
        {
            m_usConnFailed = 0;            
            strContextCn = QString("串口继电器通信恢复.");
            strContextEn = QString("serial trigger communicate recovered.");
            saveLogToBaDb(strContextCn, strContextEn);
        }
    }
    else
        ;

    //if (usConnFailed || hasEmertStopAlarm()) // 通迅故障也作为急停处理 道威7.5MWh
    //if (hasEmertStopAlarm())
    //if (m_usConnFailed || hasEmertStopAlarm() || m_fuseAlarm > 0)
    if (hasEmertStopAlarm() || m_fuseAlarm > 0)
    {
        SetEmergeStopAlarm(1);
    }
    else
    {
        SetEmergeStopAlarm(0);
    }

    sendLog(0, QString("runCount:%1, readDiCount:%2, failedCount:%3, connAlarmCount:%4, m_usConnFailed:%5")
                   .arg(runCount).arg(KgGlobalData::ms_dryData.readDiCount).arg(KgGlobalData::ms_dryData.failedCount).arg(connAlarmCount).arg(m_usConnFailed));
    if (m_usConnFailed)
    {
        sendLog(0, "******Connect IO dev Failed");
    }
}


quint16 oldFireAlarm = 0;
quint16 oldThunderAlarm = 0;
quint16 oldEmergStopAlarm = 0;
int printCount = 0;
#define PINTT_COUNT 300
void DryCtrlThread::printRealState(quint16 usHasProt, quint16 usEmergStopAlarm)
{
    if (printCount < PINTT_COUNT)
    {
        printCount += 1;

        quint16 lcConnFault = m_pStack->usStackTemp[0];// 通讯故障
        quint16 lcDevFault =  m_pStack->usStackTemp[3];// 故障状态


        //if (1 == KgGlobalData::ms_usLanuage)
        if (0)
        {
            //printf("$$$$$$$$$$$$$$$$$ Some Data $$$$$$$$$$$$$$$$$\n");
            printf("[ ****** StackState:%d, HasProt:%d, XfWarmMsg:%d, FireAlarm:%d, FireFaultAlarm:%d, FireSprayAlarm:%d]\n",
                   m_stackState, usHasProt, m_xfWarmMsg, m_fireAlarm, m_fireFaultAlarm, m_fireSprayAlarm);
            printf("[ ****** WaterAlarm:%d-%d(aEnvWaterAlarm[0]:%d), ThunderAlarm:%d, EmergStopAlarm:%d, FuseAlarm:%d, CombusGasAlarm:%d]\n",
                   m_waterAlarm, m_waterAlarmSec, (int)m_pStack->aEnvWaterAlarm[0], m_thunderAlarm, m_emergStopAlarm, m_fuseAlarm, m_combusGasAlarm);
            printf("[ ****** DIState:%d, DOState:%d, ConfSwitchState:%d, BmsLocalState:%d, BmsRemoteState:%d, UpsAlarm:%d, DoorAlarm:%d, ElecPowerOffAlarm:%d]\n",
                   KgGlobalData::ms_dryData.DIVal, KgGlobalData::ms_dryData.IOCtrl, getConfSwitchState(), m_bmsLocalState,
                   m_upsAlarm, m_doorAlarm, m_elecPowerOffAlarm);
            printf("[ ****** LcConnFault:%d, lcDevFault:%d]\n", lcConnFault, lcDevFault);
        }
        else
        {
            QString strLog;
            // modified 2024-12-11
            strLog = QString("aEnvTemp[0]to[7]:%1-%2-%3-%4-%5-%6-%7-%8,aEnvTemp[32]to[39]:%9-%10-%11-%12-%13-%14-%15-%16")
                         .arg((int)m_pStack->aEnvTemp[0]).arg((int)m_pStack->aEnvTemp[1]).arg((int)m_pStack->aEnvTemp[2])
                         .arg((int)m_pStack->aEnvTemp[3]).arg((int)m_pStack->aEnvTemp[4]).arg((int)m_pStack->aEnvTemp[5])
                         .arg((int)m_pStack->aEnvTemp[6]).arg((int)m_pStack->aEnvTemp[7])
                         .arg((int)m_pStack->aEnvTemp[32]).arg((int)m_pStack->aEnvTemp[33]).arg((int)m_pStack->aEnvTemp[34])
                         .arg((int)m_pStack->aEnvTemp[35]).arg((int)m_pStack->aEnvTemp[36]).arg((int)m_pStack->aEnvTemp[37])
                         .arg((int)m_pStack->aEnvTemp[38]).arg((int)m_pStack->aEnvTemp[39]);
            writeKgLogfile(strLog, true);

            // strLog = QString("防雷告警:%1,熔断告警:%2,可燃气体:%3,UPS告警:%4,门禁告警:%5-%6,市电断电:%7,液冷机通迅故障:%8-%9")
            // 	.arg(m_thunderAlarm).arg(m_fuseAlarm).arg(m_combusGasAlarm).arg(m_upsAlarm)
            // 	.arg(m_doorAlarm).arg(m_doorAlarmSec).arg(m_elecPowerOffAlarm)
            // 	.arg(lcConnFault).arg(lcDevFault);
            //             writeKgLogfile(strLog, true);

            //             QString strLog;

            if (isChLang())
            {
                strLog = QString("防雷告警:%1, 熔断告警:%2, 可燃气体:%3, UPS告警:%4, 门禁告警:%5-%6, 市电断电:%7, 液冷机通信故障:%8-%9")
                             .arg(m_thunderAlarm).arg(m_fuseAlarm).arg(m_combusGasAlarm).arg(m_upsAlarm)
                             .arg(m_doorAlarm).arg(m_doorAlarmSec).arg(m_elecPowerOffAlarm)
                             .arg(lcConnFault).arg(lcDevFault);

                writeKgLogfile(strLog, true);
            }
            else
            {
                strLog = QString("Surge Alarm:%1, Fuse Alarm:%2, Combustible Gas:%3, UPS Alarm:%4, Door Access Alarm:%5-%6, AC Power Off:%7, Liquid Cooling Communication Fault:%8-%9")
                .arg(m_thunderAlarm).arg(m_fuseAlarm).arg(m_combusGasAlarm).arg(m_upsAlarm)
                    .arg(m_doorAlarm).arg(m_doorAlarmSec).arg(m_elecPowerOffAlarm)
                    .arg(lcConnFault).arg(lcDevFault);

                writeKgLogfile(strLog, true);
            }




            if (isChLang())
            {
                strLog = QString("堆状态:%1-%2, 急停:%3-%4, 消防:%5-%6-%7-%8, 水浸:%9-%10(%11), 汇流开关:%12, 就地/远方:%13-%14, DIDO状态:%15-%16.")
                             .arg(m_stackState).arg(usHasProt)
                             .arg((int)m_emergStopAlarm).arg((int)m_emergStopAlarmSec)
                             .arg(m_xfWarmMsg).arg(m_fireAlarm).arg(m_fireFaultAlarm).arg(m_fireSprayAlarm)
                             .arg(m_waterAlarm).arg(m_waterAlarmSec).arg((int)m_pStack->aEnvWaterAlarm[0])
                             .arg(getConfSwitchState())
                             .arg(m_bmsLocalState).arg(m_bmsRemoteState)
                             .arg(KgGlobalData::ms_dryData.DIVal).arg(KgGlobalData::ms_dryData.IOCtrl);
            }
            else
            {
                strLog = QString("Stack State:%1-%2, E-Stop:%3-%4, Fire Protection:%5-%6-%7-%8, Water Leak:%9-%10(%11), Bus Switch:%12, Local/Remote:%13-%14, DIDO State:%15-%16.")
                .arg(m_stackState).arg(usHasProt)
                    .arg((int)m_emergStopAlarm).arg((int)m_emergStopAlarmSec)
                    .arg(m_xfWarmMsg).arg(m_fireAlarm).arg(m_fireFaultAlarm).arg(m_fireSprayAlarm)
                    .arg(m_waterAlarm).arg(m_waterAlarmSec).arg((int)m_pStack->aEnvWaterAlarm[0])
                    .arg(getConfSwitchState())
                    .arg(m_bmsLocalState).arg(m_bmsRemoteState)
                    .arg(KgGlobalData::ms_dryData.DIVal).arg(KgGlobalData::ms_dryData.IOCtrl);
            }

            writeKgLogfile(strLog, true);
        }
    }
}

void DryCtrlThread::setSomeDOState()
{    
    QString strContextCn = "";
    QString strContextEn = "";
    int k;
    int doIndex;
    QString strHint;

    quint16 usHasProt = 0;
    quint16 usHasAlarm = 0;
    quint16 usChargeFull = 0;
    quint16 usDischargeEmpty = 0;
    quint16 usProhibitChgDchg = 0;
    quint16 usXfTkMotion = 0;
    quint16 usEmergStopAlarm = 0;

    // step2.获取BAMS的运行状态
    sendLog(0, QString("Waiting stack state changed..."));
    for (int k = 0; k < 25; ++k)//wait 0.5 seconds
    {
        this->msleep(20);
        if (m_stackState != KgGlobalData::ms_pStack->usStackState)
        {
            m_stackState = KgGlobalData::ms_pStack->usStackState;
            m_statChangeTime = QDateTime::currentDateTime();
            m_drvFzCount = 0;
            m_drvHzCount = 0;
            m_drvFzSuccedCount = 0;
            m_drvHzSuccedCount = 0;

            m_saveEmsCtrlHzRdCount = 0;
            m_saveEmsCtrlFzRdCount = 0;
            m_saveRejectEmsHzRdCount = 0;
            sendLog(0, QString("StackState has Changed."));
            break;
        }

        if (oldFireAlarm != m_fireAlarm) // 需要及时响应，不再延时
        {
            sendLog(0, QString("FireAlarm state has Changed."));
            break;
        }

        if (oldThunderAlarm != m_thunderAlarm) // 需要及时响应，不再延时
        {
            sendLog(0, QString("ThunderAlarm state has Changed."));
            break;
        }

        if (hasEmertStopAlarm()) // 紧急停机状态             0 - 默认  1 - 告警  2 - 正常
        {
            usEmergStopAlarm = 1;
        }
        else
        {
            usEmergStopAlarm = 0;
        }

        if (oldEmergStopAlarm != usEmergStopAlarm) // 需要及时响应，不再延时
        {
            sendLog(0, QString("EmergStopAlarm state has Changed."));
            break;
        }
    }

    parseStackState(m_stackState, usHasProt, usHasAlarm, usChargeFull, usDischargeEmpty, usProhibitChgDchg);
#ifdef LSZH_PRJ
    lszhParseDLQState(usHasProt, usEmergStopAlarm);
#endif

#ifdef ND_VER_PROGRAM 		// 南都版本 added 2021-12-1
    // quint16 usConnState;  // 并网连接状态   0x1001    1 - 启动(Start Connection);  2 - 成功(Connection Successful);  3 - 结束(Process End)；
    if (2 != KgGlobalData::ms_pStack->usConnState) //  2 - 成功
    {
        usHasProt = 1;
    }
#endif
    printRealState(usHasProt, usEmergStopAlarm);

#ifdef LYGWK_PRJ
    usHasAlarm = isBankAlarm();// 有实时告警时才算有告警，不看总状态0x1111, 0x2222  连云港威控项目-V3.4.7版
#endif
    oldFireAlarm = m_fireAlarm;
    oldThunderAlarm = m_thunderAlarm;
    oldEmergStopAlarm = usEmergStopAlarm;

    QChar fillChar = '0';
    QString strState = QString("%1").arg(m_stackState,4,16,fillChar).toUpper();
    strHint = QString("State:0X%1, HasProt:%2, HasAlarm:%3, ChgFull:%4, DischgEmpty:%5.")
                  .arg(strState).arg(usHasProt).arg(usHasAlarm).arg(usChargeFull).arg(usDischargeEmpty);
    sendLog(0, strHint);

    quint16 olDoState = KgGlobalData::ms_dryData.IOCtrl;
    quint16 newIOCtrl = KgGlobalData::ms_dryData.IOCtrl;

    // 要先设置干结点，再控制合闸分闸, 因为分闸有延时

    // ============================step1:设置故障干结点
    for (k = 0; k < KgGlobalData::ms_gzCtrlList.size(); ++k)
    {
        DOStrategy stg = KgGlobalData::ms_gzCtrlList[k];
        quint16 usAllProt =  usHasProt | m_fireAlarm | m_fireFaultAlarm | m_fireSprayAlarm | m_waterAlarm | m_thunderAlarm | usEmergStopAlarm | m_combusGasAlarm;
        /*if (0 == k && 1== KgGlobalData::ms_saveHlkgLog)
		{
			if (usAllProt && !m_usOldHasProt)// added 2021-07-16 
			{
				if (isChLang())
				   saveLogToBaDb(kgConvert("打开故障干结点(DO%1).").arg(stg.doIndex+1));
				else
				   saveLogToBaDb(kgConvert("Open fault dry contact(DO%1).").arg(stg.doIndex+1));
			}
			if (!usAllProt && m_usOldHasProt)
			{
				if (isChLang())
				   saveLogToBaDb(kgConvert("关闭故障干结点(DO%1).").arg(stg.doIndex+1));
				else
				   saveLogToBaDb(kgConvert("Close fault dry contact(DO%1).").arg(stg.doIndex+1));
			}
			// 有故障，打开干节点
			// 无故障，关闭干节点
			m_usOldHasProt = usAllProt; 
		}*/
        setDoState(newIOCtrl, stg.doIndex, usAllProt);
    }

    // ============================step2:设置运行灯干结点 added 2021-2-26
    for (k = 0; k < KgGlobalData::ms_runCtrlList.size(); ++k)
    {
        DOStrategy stg = KgGlobalData::ms_runCtrlList[k];
        if (usHasProt | m_fireAlarm | m_fireFaultAlarm | m_fireSprayAlarm | m_waterAlarm | m_thunderAlarm | usEmergStopAlarm | m_fuseAlarm | hasCombusGasAlarm())
        {
            setDoState(newIOCtrl, stg.doIndex, 0); // 有故障，关闭运行灯
        }
        else
        {
            setDoState(newIOCtrl, stg.doIndex, 1); // 无故障，打开运行灯
        }
    }

    // ============================ added 2023-11-16 常亮灯
    for (k = 0; k < KgGlobalData::ms_allLightCtrlList.size(); ++k)
    {
        DOStrategy stg = KgGlobalData::ms_allLightCtrlList[k];
        setDoState(newIOCtrl, stg.doIndex, 1); // 常亮灯
    }

    // ============================step3:设置告警干结点
    for (k = 0; k < KgGlobalData::ms_alarmCtrlList.size(); ++k)
    {
        DOStrategy stg = KgGlobalData::ms_alarmCtrlList[k];
        if (0 == k && 1== KgGlobalData::ms_saveHlkgLog)
        {
            if (usHasAlarm && !m_usOldHasAlarm)// added 2021-07-16
            {                
                strContextCn = QString("打开告警干结点")+ QString("(DO%1).").arg(stg.doIndex+1);
                strContextEn = QString("Open alarm dry contact(DO%1).").arg(stg.doIndex+1);
                saveLogToBaDb(strContextCn, strContextEn);
            }
            if (!usHasAlarm && m_usOldHasAlarm)
            {
                strContextCn = QString("关闭告警干结点")+ QString("(DO%1).").arg(stg.doIndex+1);
                strContextEn = QString("Close alarm dry contact(DO%1).").arg(stg.doIndex+1);
                saveLogToBaDb(strContextCn, strContextEn);
            }
            // 有告警，打开干节点
            // 无告警，关闭干节点
            m_usOldHasAlarm = usHasAlarm;
        }
        setDoState(newIOCtrl, stg.doIndex, usHasAlarm);
    }

    int hasOtherAlam = 0;
#ifdef YW0357_PRJ  // added 2022-07-05
    hasOtherAlam = 0;// isBoxVolTempDiffAlarm();
#endif

    // ============================step4:设置禁充干结点
    for (k = 0; k < KgGlobalData::ms_phbChgList.size(); ++k)
    {
        DOStrategy stg = KgGlobalData::ms_phbChgList[k];
        setDoState(newIOCtrl, stg.doIndex, hasOtherAlam | usHasProt | m_fireAlarm | m_fireFaultAlarm | m_fireSprayAlarm | m_waterAlarm | m_thunderAlarm | usEmergStopAlarm  | m_fuseAlarm | usChargeFull | usProhibitChgDchg |hasCombusGasAlarm());
    }

    // ============================step5:设置禁放干结点
    for (k = 0; k < KgGlobalData::ms_phbDischgList.size(); ++k)
    {
        DOStrategy stg = KgGlobalData::ms_phbDischgList[k];
        setDoState(newIOCtrl, stg.doIndex, hasOtherAlam | usHasProt | m_fireAlarm | m_fireFaultAlarm | m_fireSprayAlarm | m_waterAlarm | m_thunderAlarm | usEmergStopAlarm  | m_fuseAlarm | usDischargeEmpty | usProhibitChgDchg |hasCombusGasAlarm());
    }

    // ============================step6:设置充电驱动干结点
    for (k = 0; k < KgGlobalData::ms_chgDriveList.size(); ++k)
    {
        DOStrategy stg = KgGlobalData::ms_chgDriveList[k];
        if (usHasProt | m_fireAlarm | m_fireFaultAlarm | m_fireSprayAlarm | m_waterAlarm | m_thunderAlarm | usEmergStopAlarm  | m_fuseAlarm | usChargeFull | usProhibitChgDchg |hasCombusGasAlarm())
        {
            setDoState(newIOCtrl, stg.doIndex, 0);
        }
        else
        {
            setDoState(newIOCtrl, stg.doIndex, 1);
        }
    }

    // ============================step7:设置放电驱动干结点
    for (k = 0; k < KgGlobalData::ms_dchgDriveList.size(); ++k)
    {
        DOStrategy stg = KgGlobalData::ms_dchgDriveList[k];
        if (usHasProt | m_fireAlarm | m_fireFaultAlarm | m_fireSprayAlarm | m_waterAlarm | m_thunderAlarm | usEmergStopAlarm  | m_fuseAlarm | usDischargeEmpty | usProhibitChgDchg |hasCombusGasAlarm())
        {
            setDoState(newIOCtrl, stg.doIndex, 0);
        }
        else
        {
            setDoState(newIOCtrl, stg.doIndex, 1);
        }
    }

    // added 2024-5-8
    for (k = 0; k < KgGlobalData::ms_keepRegCtrlDriveList.size(); ++k)
    {
        DOStrategy stg = KgGlobalData::ms_keepRegCtrlDriveList[k];
        if (KgGlobalData::ms_keepRegCtrlPos > 49)
            KgGlobalData::ms_keepRegCtrlPos = 49;
        int ctrlVal = KgGlobalData::ms_pStack->usStackHoldTemp[KgGlobalData::ms_keepRegCtrlPos];
        if (ctrlVal > 0)
        {
            setDoState(newIOCtrl, stg.doIndex, 1);
        }
        else
        {
            setDoState(newIOCtrl, stg.doIndex, 0);
        }
    }

    // ============================step8:设置消防动作干结点
    for (k = 0; k < KgGlobalData::ms_xfStrategy.xfCtrlList.size(); ++k)
    {
        DOStrategy stg = KgGlobalData::ms_xfStrategy.xfCtrlList[k];
        setDoState(newIOCtrl, stg.doIndex, m_fireAlarm | m_fireFaultAlarm | m_fireSprayAlarm /*|m_fireDetectAlarm*/| m_waterAlarm | m_thunderAlarm | hasCombusGasAlarm());
    }

    //  ============================step8:设置消防喷洒动作干结点
    for (k = 0; k < KgGlobalData::ms_xfSprayStrategy.xfCtrlList.size(); ++k) // added 2022-12-10
    {
        DOStrategy stg = KgGlobalData::ms_xfSprayStrategy.xfCtrlList[k];
        setDoState(newIOCtrl, stg.doIndex, m_fireSprayAlarm);
    }

    // ============================step9:设置防雷动作干结点
    for (k = 0; k < KgGlobalData::ms_tdStrategy.xfCtrlList.size(); ++k)
    {
        DOStrategy stg = KgGlobalData::ms_tdStrategy.xfCtrlList[k];
        setDoState(newIOCtrl, stg.doIndex, m_thunderAlarm);
    }

    // ============================step10:设置BMS-EMS通信故障干结点
    for (k = 0; k < KgGlobalData::ms_bmsEmsCommFaultList.size(); ++k)
    {
        DOStrategy stg = KgGlobalData::ms_bmsEmsCommFaultList[k];
        quint16 usCommFault = 0;
#ifdef ND_VER_PROGRAM 	// 南都版本 
        // Bit3: EMS通信故障报警;  Bit2: EMS communication fault alarm; 
        if ((KgGlobalData::ms_pStack->usStackTotAlarm & (1 << 3)) > 0)
        {
            usCommFault = 1;
        }
#endif
        setDoState(newIOCtrl, stg.doIndex, usCommFault);
    }

    // ============================驱动风扇 added 2023-5-19
    for (k = 0; k < KgGlobalData::ms_fanDriveList.size(); ++k)
    {
        DOStrategy stg = KgGlobalData::ms_fanDriveList[k];
        float fStackCur = fabs(KgGlobalData::ms_pStack->fStackCur);
        /*if (m_fireAlarm || m_fireSprayAlarm || usEmergStopAlarm || fStackCur < 10)
		{
			setDoState(stg.doIndex, 0); // 没有充放电，关闭风扇
		}
		else
		{
			setDoState(stg.doIndex, 1); // 有充放电，打开风扇
		}*/

        // modified 2023-12-17
        if (m_fireAlarm || m_fireSprayAlarm || usEmergStopAlarm || fStackCur < KgGlobalData::ms_minChgDchgCur)
        {
            if (0 == m_oldCtrlFanState)
            {
                setDoState(newIOCtrl, stg.doIndex, 0); // 没有充放电，关闭风扇
            }
            else // 有驱动过风扇, 延时关闭
            {
                if (0 == m_closeFanReqCount)
                {
                    m_closeReqStartTime = QDateTime::currentDateTime();
                    m_closeFanReqCount += 1;
                }
                else
                {
                    QDateTime nowTime = QDateTime::currentDateTime();
                    int elapseSec  = m_closeReqStartTime.secsTo(nowTime);
                    if (elapseSec >= KgGlobalData::ms_closeFanDelayTime)
                    {
                        m_oldCtrlFanState = 0; // 驱动风扇标记清0
                    }
                }
            }
        }
        else
        {
            m_oldCtrlFanState = 1; // 驱动风扇标记
            m_closeFanReqCount = 0;
            setDoState(newIOCtrl, stg.doIndex, 1); // 有充放电，打开风扇
        }
    }

    // ============================温度驱动 added 2024-4-26
    for (k = 0; k < KgGlobalData::ms_tempDriveList.size(); ++k)
    {
        DOStrategy stg = KgGlobalData::ms_tempDriveList[k];
        if (KgGlobalData::ms_pStack->fSglMaxTempInStack > KgGlobalData::ms_openFanTemp)
        {
            setDoState(newIOCtrl, stg.doIndex, 1);
        }
        else
        {
            setDoState(newIOCtrl, stg.doIndex, 0);
        }
    }

    // 合闸口默认是断开的 added 2021-7-20
    for (k = 0; k < KgGlobalData::ms_hlkgStrategy.hzDoList.size(); ++k)
    {
        doIndex = KgGlobalData::ms_hlkgStrategy.hzDoList[k];
        //KgGlobalData::ms_dryData.IOCtrl &= ~(1 << doIndex);
        newIOCtrl &= ~(1 << doIndex);
    }

    // 分闸口默认是断开的
    for (k = 0; k < KgGlobalData::ms_hlkgStrategy.fzDoList.size(); ++k)
    {
        doIndex = KgGlobalData::ms_hlkgStrategy.fzDoList[k];
        newIOCtrl &= ~(1 << doIndex);
    }

    // 消防脱扣分闸口默认是断开的
    for (k = 0; k < KgGlobalData::ms_hlkgStrategy.xfTkDoList.size(); ++k)
    {
        doIndex = KgGlobalData::ms_hlkgStrategy.xfTkDoList[k];
        newIOCtrl &= ~(1 << doIndex);
    }

    // 消防喷洒脱扣分闸口默认是断开的
    for (k = 0; k < KgGlobalData::ms_hlkgStrategy.xfSprayTkDoList.size(); ++k)
    {
        doIndex = KgGlobalData::ms_hlkgStrategy.xfSprayTkDoList[k];
        newIOCtrl &= ~(1 << doIndex);
    }

    // 低电压保护分励脱扣默认是断开的
    for (k = 0; k < KgGlobalData::ms_hlkgStrategy.volDownProtFzDoList.size(); ++k)
    {
        doIndex = KgGlobalData::ms_hlkgStrategy.volDownProtFzDoList[k];
        newIOCtrl &= ~(1 << doIndex);
    }

    /*
    setBankDoState(fireAlarm);
	setDoState(0,usHasProt | fireAlarm);                   //为报警灯
	setDoState(1,usHasProt | fireAlarm | usChargeFull);    //为禁充干结点
	setDoState(2,usHasProt | fireAlarm | usDischargeEmpty);//为禁放干结点
	*/

    /*
    //设置故障灯DO3
    setDoState(2, usHasProt | fireAlarm);
   
    //设置排风扇继电器DO4
    setDoState(3, fireAlarm);
   
    //设置空调继电器DO5
    setDoState(4, fireAlarm);
   
    //设置协控DO6
    setDoState(5, usHasProt | fireAlarm);
    */
    //sendLog(0, QString("olDoState:%1, IOCtrl:%2").arg(olDoState).arg((int)KgGlobalData::ms_dryData.IOCtrl));


    if (olDoState != newIOCtrl) // DO状态发生了变化，才下发  || 0 == m_setDoCount
    {
        m_pIOReader->AddSetCmd(0, newIOCtrl,0);
    }
    m_pIOReader->DealwithSetDoCmd(0, KgGlobalData::ms_dryData); // 执行设置故障灯，运行灯等命令
}

int g_xfSprayCount = 0;
void DryCtrlThread::controlOtherFz()  
{
    QString strContextCn = "";
    QString strContextEn = "";
    // 1 == m_fireAlarm  ||
    //if (1 == m_fireAlarm || 1 == m_fireFaultAlarm || 1 == m_fireSprayAlarm || 1 == m_combusGasAlarm || 1 == m_waterAlarm) // 发生了消防告警
    if (1 == m_fireAlarm || 1 == m_fireSprayAlarm || (hasEmertStopAlarm() && isEmgTkEnabled()) ||
        (hasWaterAlarm() && isWaterTkEnabled()) ) // 发生了消防告警 // modified 2023-3-13
    {
        writeKgLogfile(QString("========================== controlOtherFz 888 %1 m_xfTkMotionCount:%2")
                           .arg(KgGlobalData::ms_hlkgStrategy.xfTkDoList.size()).arg(m_xfTkMotionCount));
        // 109 == iStrategy
        // 有消防脱扣干节点 added 2021-10-29
        if (KgGlobalData::ms_hlkgStrategy.xfTkDoList.size() > 0 && (m_xfTkMotionCount < 3 ||
                                                                    getClosedConfSwitchCount() > 0)) // 发生消防告警，只执行消防脱扣2次
        {
            ++m_xfTkMotionCount;

            //int doIndex = KgGlobalData::ms_hlkgStrategy.xfTkDoList.at(0);
            QString strDoName = getDOName(KgGlobalData::ms_hlkgStrategy.xfTkDoList);
            openDos(KgGlobalData::ms_dryData.IOCtrl, KgGlobalData::ms_hlkgStrategy.xfTkDoList);
            //openDos(KgGlobalData::ms_dryData.IOCtrl, KgGlobalData::ms_hlkgStrategy.fzDoList);// added 2022-11-17
            int delayTime = KgGlobalData::ms_tkDelayTime * 1000;
            m_pIOReader->AddSetCmd(0,KgGlobalData::ms_dryData.IOCtrl,delayTime);

            if (1 == m_fireAlarm && 0 == m_xfTkMotionLogCount)
            {
                m_xfTkMotionLogCount = 1;
                strContextCn = QString("消防告警,分励脱扣") + QString("(%1).").arg(strDoName);
                strContextEn = QString("Fire alarm, shunt trip switch(%1).").arg(strDoName);
                saveLogToBaDb(strContextCn, strContextEn);
            }

            if (1 == m_fireSprayAlarm && 0 == m_xfSprayTkMotionLogCount)
            {
                m_xfSprayTkMotionLogCount = 1;
                strContextCn = QString("消防喷洒,分励脱扣") + QString("(%1).").arg(strDoName);
                strContextEn = QString("Fire spray alarm, shunt trip switch(%1).").arg(strDoName);
                saveLogToBaDb(strContextCn, strContextEn);
            }

            if (hasEmertStopAlarm() && isEmgTkEnabled() && 0 == m_emgTkMotionLogCount)
            {
                m_emgTkMotionLogCount = 1;
                strContextCn = QString("急停,分励脱扣") + QString("(%1).").arg(strDoName);
                strContextEn = QString("Emergency, shunt trip switch(%1).").arg(strDoName);
                saveLogToBaDb(strContextCn, strContextEn);
            }

            closeDos(KgGlobalData::ms_dryData.IOCtrl, KgGlobalData::ms_hlkgStrategy.xfTkDoList);
            //closeDos(KgGlobalData::ms_dryData.IOCtrl, KgGlobalData::ms_hlkgStrategy.fzDoList);// added 2022-11-17

            m_pIOReader->AddSetCmd(0,KgGlobalData::ms_dryData.IOCtrl,0);
            m_pIOReader->DealwithSetDoCmd(0,KgGlobalData::ms_dryData);
            this->msleep(200);

            if (KgGlobalData::ms_hlkgStrategy.fzDoList.size() > 0) // added 2022-11-17
            {
                //m_drvFzSuccedCount += 1;
            }
        }
    }
    else
    {
        m_xfTkMotionCount = 0;

        m_xfTkMotionLogCount = 0;
        m_xfSprayTkMotionLogCount = 0;
        m_emgTkMotionLogCount = 0;
    }

    if (1 == m_fireSprayAlarm || (hasEmertStopAlarm() && isEmgTkEnabled()) ||
        (hasWaterAlarm() && isWaterTkEnabled())) // 发生了消防喷洒告警 // added 2022-12-10
    {
        writeKgLogfile(QString("========================== controlOtherFz 889 %1 m_xfSprayTkMotionCount:%2")
                           .arg(KgGlobalData::ms_hlkgStrategy.xfSprayTkDoList.size()).arg(m_xfSprayTkMotionCount));
        if (g_xfSprayCount < 1000)
        {
            g_xfSprayCount += 1;
        }
        // 110 == iStrategy
        // 有消防喷洒脱扣干节点 g_xfSprayCount >= 15 &&
        if (KgGlobalData::ms_hlkgStrategy.xfSprayTkDoList.size() > 0 && (m_xfSprayTkMotionCount < 3 ||
                                                                         getClosedConfSwitchCount() > 0)) // 发生消防喷洒脱告警，只执行脱扣2次
        {
            ++m_xfSprayTkMotionCount;

            //int doIndex = KgGlobalData::ms_hlkgStrategy.xfSprayTkDoList.at(0);
            QString strDoName = getDOName(KgGlobalData::ms_hlkgStrategy.xfSprayTkDoList);
            openDos(KgGlobalData::ms_dryData.IOCtrl, KgGlobalData::ms_hlkgStrategy.xfSprayTkDoList);// 先闭合
            int delayTime = KgGlobalData::ms_tkDelayTime * 1000;
            m_pIOReader->AddSetCmd(0,KgGlobalData::ms_dryData.IOCtrl,delayTime);

            if (1 == m_fireSprayAlarm && 0 == m_xfSprayTkMotionLogCount)
            {
                m_xfSprayTkMotionLogCount = 1;
                strContextCn = QString("消防喷洒分励脱扣") + QString("(%1).").arg(strDoName);
                strContextEn = QString("Fire spray alarm, opening switch(%1).").arg(strDoName);
                saveLogToBaDb(strContextCn, strContextEn);
            }

            if (hasEmertStopAlarm() && isEmgTkEnabled() && 0 == m_emgTkMotionLogCount)
            {
                m_emgTkMotionLogCount = 1;
                strContextCn = QString("急停,分励脱扣") + QString("(%1).").arg(strDoName);
                strContextEn = QString("Emergency, shunt trip switch(%1).").arg(strDoName);
                saveLogToBaDb(strContextCn, strContextEn);
            }

            closeDos(KgGlobalData::ms_dryData.IOCtrl, KgGlobalData::ms_hlkgStrategy.xfSprayTkDoList);// 再断开

            m_pIOReader->AddSetCmd(0,KgGlobalData::ms_dryData.IOCtrl,0);
            m_pIOReader->DealwithSetDoCmd(0,KgGlobalData::ms_dryData);
            this->msleep(200);

            if (KgGlobalData::ms_hlkgStrategy.fzDoList.size() > 0) // added 2022-11-17
            {
                //m_drvFzSuccedCount += 1;
            }
        }
    }
    else
    {
        m_xfSprayTkMotionCount = 0;

        m_xfSprayTkMotionLogCount = 0;
        m_emgTkMotionLogCount = 0;
        g_xfSprayCount = 0;
    }

    bool isVolDownProt = hasVolDownPort();
    if (isVolDownProt)
    {
        if (KgGlobalData::ms_hlkgStrategy.volDownProtFzDoList.size() > 0 && m_volDownProtTkCount < 3)
        {
            m_volDownProtTkCount += 1;
            // 103 == iStrategy
            //int doIndex = KgGlobalData::ms_hlkgStrategy.volDownProtFzDoList.at(0);
            QString strDoName = getDOName(KgGlobalData::ms_hlkgStrategy.xfSprayTkDoList);
            openDos(KgGlobalData::ms_dryData.IOCtrl, KgGlobalData::ms_hlkgStrategy.volDownProtFzDoList);// 先闭合
            int delayTime = KgGlobalData::ms_tkDelayTime * 1000;
            m_pIOReader->AddSetCmd(0,KgGlobalData::ms_dryData.IOCtrl,delayTime);
            if (0 == m_volDownProtTkLogCount)
            {
                m_volDownProtTkLogCount = 1;
                strContextCn = QString("低电压保护分励脱扣") + QString("(%1).").arg(strDoName);
                strContextEn = QString("Vol down protect, opening switch(%1).").arg(strDoName);
                saveLogToBaDb(strContextCn, strContextEn);
            }

            closeDos(KgGlobalData::ms_dryData.IOCtrl, KgGlobalData::ms_hlkgStrategy.volDownProtFzDoList);// 再断开
            m_pIOReader->AddSetCmd(0,KgGlobalData::ms_dryData.IOCtrl,0);
            m_pIOReader->DealwithSetDoCmd(0,KgGlobalData::ms_dryData);
            this->msleep(200);

            if (KgGlobalData::ms_hlkgStrategy.fzDoList.size() > 0) // added 2022-11-17
            {
                //m_drvFzSuccedCount += 1;
            }
        }
    }
    else
    {
        m_volDownProtTkCount = 0;
        m_volDownProtTkLogCount = 0;
    }
}

//控制DO口是否闭合(打开继电器)
bool DryCtrlThread::setDoState0(quint16 doIndex, quint16 usSetVal)
{
    /*
	操作DO  打开第1个继电器
	发送:FE 05 00 00 FF 00 98 35 
	接收:FE 05 00 00 FF 00 98 35 
	*/
    unsigned short cmd = 0;
    QString strLog;
    //msleep(50);//msleep(300);

    if (usSetVal)//需要打开
    {
        //strLog = QString("==================usSetVal:%1, set DO%2 to open").arg(usSetVal).arg(doIndex+1);
        strLog = QString("UsSetVal:%1, set DO%2 to open.").arg(usSetVal).arg(doIndex+1);
        sendLog(0, strLog);
        //g_DOState |= (1 << doIndex);
        KgGlobalData::ms_dryData.IOCtrl |= (1 << doIndex);
    }
    else
    {
        //strLog = QString("==================usSetVal:%1, set DO%2 to close").arg(usSetVal).arg(doIndex+1);
        strLog = QString("UsSetVal:%1, set DO%2 to close.").arg(usSetVal).arg(doIndex+1);
        sendLog(0, strLog);
        //g_DOState &= ~(1 << doIndex);
        KgGlobalData::ms_dryData.IOCtrl &= ~(1 << doIndex);
    }

    return true;////////////////////////////

    /*
    sendCtrlDoCmd(doIndex, usSetVal);
	
	int iRetVal = readDevReplay(doIndex+1, 8);
	if (iRetVal >= 8)
	{
		//
		//iRetVal = analySetSingleDatagram(m_devAddr, m_pDataBuf, iRetVal, doIndex, cmd);
		//if (0 != iRetVal)
		//{
		//   sendLog(RUN_LOG_FAILED_DEV, QString("analyRtuDatagram ret:%1").arg(iRetVal));
		//}
		//return iRetVal;
		g_connFailedCount = 0;
	}
	else
	{
	   iRetVal = -2;
	   if (g_connFailedCount < 50000)
		{
			g_connFailedCount += 1;
		}
	}

	return iRetVal;	
	*/
}

//控制DO口是否闭合(打开继电器)
bool DryCtrlThread::setDoState(quint16 &IOCtrl, quint16 doIndex, quint16 usSetVal)
{
    unsigned short cmd = 0;
    QString strLog;

    if (usSetVal)//需要打开
    {
        strLog = QString("UsSetVal:%1, set DO%2 to open.").arg(usSetVal).arg(doIndex+1);
        sendLog(0, strLog);
        //g_DOState |= (1 << doIndex);
        IOCtrl |= (1 << doIndex);
    }
    else
    {
        strLog = QString("UsSetVal:%1, set DO%2 to close.").arg(usSetVal).arg(doIndex+1);
        sendLog(0, strLog);
        //g_DOState &= ~(1 << doIndex);
        IOCtrl &= ~(1 << doIndex);
    }

    return true;////////////////////////////
}

void DryCtrlThread::readDIValue(quint16 runCount)
{
    int ret = readDevDIState(KgGlobalData::ms_pStack, KgGlobalData::ms_dryData.failedCount);

    // 刚检测到有消防信号，或防雷信号，或急停信号,但还没报警, 再读一次进行确认 // added 2021-3-25
    if ((m_fireAlarmCount > 0 && m_fireAlarmCount < KgGlobalData::ms_xfStrategy.confirmedCount) ||
        (m_thunderCount > 0 && m_thunderCount < KgGlobalData::ms_tdStrategy.confirmedCount) ||
        (m_emergStopCount > 0 && m_emergStopCount < KgGlobalData::ms_emgStopStrategy.confirmedCount) ||
        (m_fuseCount > 0 && m_fuseCount < KgGlobalData::ms_fuseStrategy.confirmedCount))
    {
        this->msleep(500);//200
        ret = readDevDIState(KgGlobalData::ms_pStack, KgGlobalData::ms_dryData.failedCount);
    }

    //dealwithConnFailed(runCount); // deleted 2023-11-9

    QString strHint = QString("DIState:%1, DOState:%2, drvFzCnt:%3, drvHzCnt:%4")
                          .arg(KgGlobalData::ms_dryData.DIVal).arg(KgGlobalData::ms_dryData.IOCtrl).arg(m_drvFzCount).arg(m_drvHzCount);
    //if (KgGlobalData::ms_hlkgStrategy.diCfg.diIndex < KgGlobalData::ms_devDiCount) // 有采集汇流开关反馈
    if (KgGlobalData::ms_hlkgStrategy.diCfgList.size() > 0)
    {
        strHint += QString(", hlkgState:%1.").arg(getConfSwitchStrState());
    }
    sendLog(0, strHint);

    strHint = QString("***FireAlarm:%1-%2-%3, thunderAlarm:%4-%5-%6, emergStopAlarm:%7-%8-%9.")
                  .arg(KgGlobalData::ms_xfStrategy.diList.size()).arg(m_fireAlarmCount).arg(m_fireAlarm)
                  .arg(KgGlobalData::ms_tdStrategy.diList.size()).arg(m_thunderCount).arg(m_thunderAlarm)
                  .arg(KgGlobalData::ms_emgStopStrategy.diList.size()).arg(m_emergStopCount).arg(m_emergStopAlarm);
    sendLog(0, strHint);

    if (KgGlobalData::ms_dryData.readDiCount > 0)
    {
        //SetBamsFireAlarm(m_fireAlarm | hasCombusGasAlarm());
        //SetBamsWaterAlarm(m_waterAlarm);
        //SetFuseAlarm(m_fuseAlarm); // deleted 2022-11-16
        //SetBamsFireAlarm(m_waterAlarm); // 华电新乡，水浸当做消防处理 2021-12-1
    }
}

//printf("pStack->usDI2================%d\n", pStack->usDI2);

/* test 2020-9-27
sendLog(RUN_LOG_FAILED_DEV, QString("usConfSwitchStrategy:%1").arg(pStack->usConfSwitchStrategy));
if (200 ==pStack->usConfSwitchStrategy)// 汇流开关策略 200 - 3rd进程设定 汇流开关断开,才能闭合接触器
	{
    pStack->usConfSwitchState = 0;//通知BA 汇流开关已经闭合
    sendLog(RUN_LOG_FAILED_DEV, "pStack->usConfSwitchState = 1");
}*/

/*if (++test ==1)
{
    // QString strLog = "EMS control confluence switch closing";
    // QString strLog = "EMS control confluence switch opening";
    // QString strLog = "EMS 控制汇流开关合闸";
	saveLogToBaDb(EMS_CTRL_SWITCH_CLOSE_STR);
}*/

// 获取总交流断路器，直流断路器总合闸个数
int DryCtrlThread::GetCloseDlqCount()
{
    int count = 0;
    CIOModule *pIOModule = ::getIOModule();// KgGlobalData::ms_pRTDB->getIOModule();

    for (int k = 0;  k < KgGlobalData::ms_installBankNum; ++k)
    {
        if (isBankInStack(k))
        {
            if (pIOModule->usDI[3+k] > 0) // 簇直流断路器为合闸状态
            {
                count += 1;
            }
        }
    }

    if (pIOModule->usDI[13] > 0)// 总交流断路器为合闸状态
    {
        count += 1;
    }

    return count;
}

void DryCtrlThread::JudgeXfMotion(int &xfAlarmCount, int &xfMotionCount, int &xfErrorCount, int &xfctrlDlqCount, int runCount)
{
    QString strContextCn = "";
    QString strContextEn = "";
    CIOModule *pIOModule = KgGlobalData::ms_pIOModule;
    CBattStack *pStack = KgGlobalData::ms_pStack;

    int xfAlarm =  pIOModule->usDI[0]; // 消防告警干接点
    int xfMotion = pIOModule->usDI[1]; // 消防动作干接点
    int xfError =  pIOModule->usDI[2]; // 消防故障干接点
    QString strHint;

    /*float fTime = runCount * 50 / 1000; // 运行时间计时，单位：秒
	if (fTime >= 15 && fTime <= 135)
	{
		xfMotion = 1; // 模拟消防动作
	}*/

    if (xfAlarm) // 消防告警
    {
        if (xfAlarmCount < 2000)
            xfAlarmCount += 1;

        if (xfAlarmCount >= 20) // 确认消防告警 1S
        {
            if ((runCount % 100) == 0) // 每5秒输出一次
            {
                strHint = QString("===================aFireWarn xfAlarmCount:%1").arg(xfAlarmCount);
                writeKgLogfile(strHint);
            }
            //pStack->aFireWarn = 1;
            if (0 == m_xfAlarmLog)
            {
                strContextEn = "fire alarm starting.";
                saveLogToBaDb("发生消防告警.", strContextEn);
                m_xfAlarmLog = 1;
            }
        }
    }
    else
    {
        xfAlarmCount = 0;
        //pStack->aFireWarn = 0;
        if (1 == m_xfAlarmLog)
        {
            strContextEn = "fire alarm finished.";
            saveLogToBaDb("消防告警结束.", strContextEn);
            m_xfAlarmLog = 0;
        }
    }

    if (xfMotion > 0)// 消防动作
    {
        if (xfMotionCount < 2000)
            xfMotionCount += 1;

        if (xfMotionCount >= 4) // 确认消防动作 0.2S
        {
            if ((xfMotionCount % 100) == 4)
            {
                strHint = QString("===================aFireAction!!! xfMotionCount:%1, xfctrlDlqCount:%2").arg(xfMotionCount).arg(xfctrlDlqCount);
                writeKgLogfile(strHint);
            }

            pStack->aFireAction = 1;

            //writeKgLogfile("step600");

            // (1) 先通知PCS
            if (0 == xfctrlDlqCount)
            {
                TellPcsError(xfMotionCount, runCount, 0);
            }
            if (0 == m_xfXfMotionLog)
            {

                strContextEn = "fire action starting.";
                saveLogToBaDb("发生消防动作.", strContextEn);
                m_xfXfMotionLog = 1;
            }
            //writeKgLogfile("step601");

            // (2) 控制总断路器断开
            int closeDqlCount = 0;
            if (xfctrlDlqCount > 0 && xfctrlDlqCount < 3) // 已经有操作控制断开, 延时一下再看操作结果
            {
                closeDqlCount = GetCloseDlqCount();
                //writeKgLogfile(QString("step601-1  closeDqlCount:%1").arg(closeDqlCount));
                if (closeDqlCount > 0) // 还有断路路没断开
                {
                    this->msleep(1000);
                    closeDqlCount = GetCloseDlqCount();
                    //writeKgLogfile("step601-2");
                }

                if (0 == closeDqlCount) // 已全部断开，操作结束
                {
                    xfctrlDlqCount = 3;
                }
            }
            //writeKgLogfile("step602");

            if (0 == xfctrlDlqCount || (xfctrlDlqCount < 3 && closeDqlCount > 0))// 为第一次操作 或为[第2，3次操作且仍有未断开]
            {
                xfctrlDlqCount += 1;
                if (xfctrlDlqCount > 1) // 第2，3次尝试分闸时才输出
                {
                    writeKgLogfile(QString("************************%1th control FZ when recevie XF motion, closeDqlCount:%2.")
                                       .arg(xfctrlDlqCount).arg(closeDqlCount));
                }

                // 消防动作被触发后，常开变常闭（维持2S），让监控配电一体柜1~10#直流断路器及总交流断路器断开
                pIOModule->usDOCtrl[0] = 1;

                for (int k = 0; k < 20; ++k)
                {
                    this->msleep(100);
                    if (5 == k || 10 == k || 15 == k)
                    {
                        printDiDoState();
                    }
                }

                pIOModule->usDOCtrl[0] = 0;
            }
            //writeKgLogfile("step603");
        }
    }
    else
    {
        xfMotionCount = 0;
        xfctrlDlqCount = 0;
        pStack->aFireAction = 0;

        if (1 == m_xfXfMotionLog)
        {
            strContextEn = "fire action finished.";
            saveLogToBaDb("消防动作结束.", strContextEn);
            //saveLogToBaDb(kgConvert(trUtf8("\xE6\xB6\x88\xE9\x98\xB2\xE5\x8A\xA8\xE4\xBD\x9C\xE7\xBB\x93\xE6\x9D\x9F\x2E")));
            m_xfXfMotionLog = 0;
        }
    }

    if (xfError)// 消防故障
    {
        if (xfErrorCount < 2000)
            xfErrorCount += 1;

        if (xfErrorCount >= 20) // 确认消防故障 1S
        {
            if ((runCount % 100) == 0) // 每5秒输出一次
            {
                strHint = QString("===================aFireFault xfErrorCount:%1").arg(xfErrorCount);
                writeKgLogfile(strHint);
            }
            //pStack->aFireFault = 1;

            if (0 == m_xfXfErrorLog)
            {
                strContextEn = "fire fault starting.";
                saveLogToBaDb("发生消防故障.", strContextEn);
                //saveLogToBaDb(kgConvert(trUtf8("\xE5\x8F\x91\xE7\x94\x9F\xE6\xB6\x88\xE9\x98\xB2\xE6\x95\x85\xE9\x9A\x9C\x2E")));
                m_xfXfErrorLog = 1;
            }
        }
    }
    else
    {
        xfErrorCount = 0;
        //pStack->aFireFault = 0;
        if (1 == m_xfXfErrorLog)
        {
            strContextEn = "fire fault finished.";
            saveLogToBaDb("消防故障结束.", strContextEn);
            //saveLogToBaDb(kgConvert(trUtf8("\xE6\xB6\x88\xE9\x98\xB2\xE6\x95\x85\xE9\x9A\x9C\xE7\xBB\x93\xE6\x9D\x9F\x2E")));
            m_xfXfErrorLog = 0;
        }
    }
}

// pStack->aEnvTemp[pos++] = retList[k++].toInt();// 水冷机 1#系统故障 !!!    aEnvTemp[0] 
// pStack->aEnvTemp[pos++] = retList[k++].toInt();// 水冷机 2#系统故障 !!!    aEnvTemp[4] 
// pStack->aEnvTemp[pos++] = retList[k++].toInt();// 水冷机 系统缺水告警 !!!  aEnvTemp[10] 
// pStack->aEnvTemp[pos++] = retList[k++].toInt();// 水冷机 电源故障告警 !!!  aEnvTemp[13] 
QString getYljErrorName(CBattStack *pStack)
{
    QString strError;
    if (pStack->aEnvTemp[0] > 0 && pStack->aEnvTemp[4] > 0)
    {
        strError = QString("1#,2#系统故障");
    }
    else if (pStack->aEnvTemp[0] > 0)
    {
        strError = QString("1#系统故障");
    }
    else if (pStack->aEnvTemp[4] > 0)
    {
        strError = QString("2#系统故障");
    }
    else
        ;

    if (pStack->aEnvTemp[10] > 0)// 系统缺水告警
    {
        if (strError.length() > 2)
        {
            strError += ",";
        }
        strError += QString("系统缺水告警");
    }

    if (pStack->aEnvTemp[13] > 0)// 电源故障告警
    {
        if (strError.length() > 2)
        {
            strError += ",";
        }
        strError += QString("电源故障");
    }

    return strError;
}

void DryCtrlThread::JudgeYljError(int &yljProtCount, int &xfctrlDlqCount, int runCount)// added 2023-10-25
{
    CIOModule *pIOModule = KgGlobalData::ms_pIOModule;
    CBattStack *pStack = KgGlobalData::ms_pStack;
    QString strHint;
    QString strContextEn = "";
    int yljProtSum = pStack->aEnvTemp[0] + pStack->aEnvTemp[4] + pStack->aEnvTemp[10] + pStack->aEnvTemp[13];
    // pStack->aEnvTemp[pos++] = retList[k++].toInt();// 水冷机 1#系统故障 !!!    aEnvTemp[0]
    // pStack->aEnvTemp[pos++] = retList[k++].toInt();// 水冷机 2#系统故障 !!!    aEnvTemp[4]
    // pStack->aEnvTemp[pos++] = retList[k++].toInt();// 水冷机 系统缺水告警 !!!  aEnvTemp[10]
    // pStack->aEnvTemp[pos++] = retList[k++].toInt();// 水冷机 电源故障告警 !!!  aEnvTemp[13]
    
    if (yljProtSum > 0)// 消防动作
    {
        if (yljProtCount < 2000)
            yljProtCount += 1;

        if (yljProtCount >= 4) // 确认保护动作 0.2S
        {
            if ((yljProtCount % 100) == 4)
            {
                strHint = QString("===================aYljError!!! yljProtCount:%1, xfctrlDlqCount:%2").arg(yljProtCount).arg(xfctrlDlqCount);
                writeKgLogfile(strHint);
            }

            //pStack->aFireAction = 1;

            //writeKgLogfile("step600");

            // (1) 先通知PCS
            if (0 == xfctrlDlqCount)
            {
                TellPcsError(yljProtCount, runCount, 0);
            }
            if (0 == m_yljErrorLog)
            {
                strContextEn = QString("water cool machine occur:%1.").arg(getYljErrorName(pStack));
                saveLogToBaDb(QString("水冷机发生:%1.").arg(getYljErrorName(pStack)), strContextEn);
                //saveLogToBaDb(kgConvert(trUtf8("\xE5\x8F\x91\xE7\x94\x9F\xE6\xB6\x88\xE9\x98\xB2\xE5\x8A\xA8\xE4\xBD\x9C\x2E")));
                m_yljErrorLog = 1;
            }
            //writeKgLogfile("step601");

            // (2) 控制总断路器断开
            int closeDqlCount = 0;
            if (xfctrlDlqCount > 0 && xfctrlDlqCount < 3) // 已经有操作控制断开, 延时一下再看操作结果
            {
                closeDqlCount = GetCloseDlqCount();
                //writeKgLogfile(QString("step601-1  closeDqlCount:%1").arg(closeDqlCount));
                if (closeDqlCount > 0) // 还有断路器没断开
                {
                    this->msleep(1000);
                    closeDqlCount = GetCloseDlqCount();
                    //writeKgLogfile("step601-2");
                }

                if (0 == closeDqlCount) // 已全部断开，操作结束
                {
                    xfctrlDlqCount = 3;
                }
            }
            //writeKgLogfile("step602");

            if (0 == xfctrlDlqCount || (xfctrlDlqCount < 3 && closeDqlCount > 0))// 为第一次操作 或为[第2，3次操作且仍有未断开]
            {
                xfctrlDlqCount += 1;
                if (xfctrlDlqCount > 1) // 第2，3次尝试分闸时才输出
                {
                    writeKgLogfile(QString("************************%1th control FZ when recevie XF motion, closeDqlCount:%2.")
                                       .arg(xfctrlDlqCount).arg(closeDqlCount));
                }

                // 消防动作被触发后，常开变常闭（维持2S），让监控配电一体柜1~10#直流断路器及总交流断路器断开
                pIOModule->usDOCtrl[0] = 1;

                for (int k = 0; k < 20; ++k)
                {
                    this->msleep(100);
                    if (5 == k || 10 == k || 15 == k)
                    {
                        printDiDoState();
                    }
                }

                pIOModule->usDOCtrl[0] = 0;
            }
            //writeKgLogfile("step603");
        }
    }
    else
    {
        yljProtCount = 0;
        xfctrlDlqCount = 0;
        //pStack->aFireAction = 0;

        if (1 == m_yljErrorLog)
        {
            strContextEn = "water cool machine fault finished.";
            saveLogToBaDb("水冷机故障结束.", strContextEn);
            m_yljErrorLog = 0;
        }
    }
}

//int g_ctrlCount[10] = {0,0,0,0,0,0,0,0,0,0};
void DryCtrlThread::TellPcsError(int xfMotionCount, int runCount, int needTkQlq)
{
    CIOModule *pIOModule = KgGlobalData::ms_pIOModule;
    CBattStack *pStack = KgGlobalData::ms_pStack;
    QString strHint;
    QString strContextEn = "";

    // 各簇的PCS故障干节点处理
    int hasSysError = 0;
    for (int k = 0;  k < KgGlobalData::ms_installBankNum; ++k)
    {
        //if (k > 1)
        //	break;
        //if (isBankInStack(k))
        {
            CBattBank *pBank = KgGlobalData::ms_pRTDB->getBank(k);
            if ((runCount % 100) == 0) // 每5秒输出一次
            {
                if (needTkQlq)
                {
                    QChar fillChar = '0';
                    QString strState = QString("0X%1").arg(pBank->usBankState,4,16,fillChar).toUpper();
                    strHint = QString("=====Bank%1 runStateDO3:%2, errStateDO4:%3,DO5State:%4, usDI1to3:%5-%6-%7,bankState:%8")
                                  .arg(k+1).arg(pBank->usDry3State).arg(pBank->usDry4State).arg(pBank->usDry5State)
                                  .arg(pBank->usDI1).arg(pBank->usDI2).arg(pBank->usDI3).arg(strState);
                    strHint += QString(",BankVol:%1V,BankCur:%2A").arg(pBank->fBankVol).arg(pBank->fBankCur);
                    if (0xAAAA == pBank->usBankState || xfMotionCount >= 4)
                    {
                        strHint += "(Tell PCS error).";
                    }
                    writeKgLogfile(strHint);
                }
            }

            // added 2023-6-30
            if (0xAAAA == pBank->usBankState)
            {
                int almLevel3 = 0;

                /*if (pBank->aSglTempRise ||	            // 电池温度温升过快               64
					pBank->aPowerLineTempRise||	         // 动力线温度温升过快             65
					pBank->aBMUConnFault     ||		     // BMU通讯故障	                   66
					pBank->aBCMUConnFault   ||		     // BCMU通讯故障                   67	
					pBank->aSglVolWireFault  ||          // 单体电压采集线故障             68
					pBank->aBankVolWireFault ||          // 总压采集线故障                 69
					pBank->aCurWireFault  ||             // 电流采集线故障                 70
					pBank->aTempWireBreak ||             // 温度采集断线                   71
					pBank->aTempShortCircuit ||          // 温度采集短路                   72
					pBank->aBMSFault ||                  // BMS设备故障                    73
					pBank->aSglVolInvalid ||             // 单体电压无效                   74
					pBank->aSglTempInvalid ||            // 单体温度无效                   75
					pBank->aBankVolInvalid ||            // 组端电压无效                   76
					pBank->aBankCurAbnormity)            // 组电流异常                     77    
					//pBank->aFireAlarm ||                 // 消防报警                       78
					//pBank->aWaterAlarm                  // 水浸报警                       79
					{
					   almLevel3 = 1;
					}

				   if (pBank->aSglTempUpLimitProt ||      // 单体温度过高保护 
					pBank->aChgTempUpLimitProt    ||
				    pBank->aDchgTempUpLimitProt   ||
				    pBank->aSglTempDownLimitProt  ||
				    pBank->aChgTempDownLimitProt  || 
				    pBank->aDchgTempDownLimitProt ||
				    pBank->aPackVolDiffUpLimitProt|| 
				    pBank->aBankSocDownLimitProt||
				    pBank->aBankSocUpLimitProt  ||
				    pBank->aPosResDownLimitProt || pBank->aNegResDownLimitProt||
					pBank->aSglVolUpLimitProt   ||// 单体电压过高保护  
					pBank->aSglVolDownLimitProt ||// 单体电压过低保护 
				    pBank->aBankVolUpLimitProt  ||// 组电压过高保护 
			        pBank->aBankVolDownLimitProt||// 组电压过低保护 
			        pBank->aChgCurUpLimitProt	||// 充电电流上限保护               
			        pBank->aDchgCurUpLimitProt	||// 放电电流上限保护               
			        pBank->aEnvTempUpLimitProt  ||// 环境温度过高保护 
			        //pBank->aEnvTempDownLimitProt  ||// 环境温度下限保护 	  
			        pBank->aPowerLineTempUpLimitProt ||// 动力线温度上限保护 
			        pBank->aPackTempDiffUpLimitProt)// 箱温差上限保护 
					{
					   almLevel3 = 1;
					}*/

                //if (almLevel3 > 0) // 有故障才开始计时
                if (1)
                {
                    if (m_bankFaultTimeCount[k] < 10000)
                    {
                        m_bankFaultTimeCount[k] += 1;
                    }
                }
                else
                {
                    m_bankFaultTimeCount[k] = 0;
                }
            }
            else
            {
                m_bankFaultTimeCount[k] = 0;
            }

            // 发生故障， 或有消防启动信号，
            if ((0xAAAA == pBank->usBankState && 0 == pBank->usNeedCloseJCQ) || (xfMotionCount >= 4))
            {
                hasSysError = 1;
                pIOModule->usDOCtrl[1+k] = 1; // PCS故障干节点

                if (needTkQlq)
                {
                    // 有消防启动信号，或  刚发生故障后3秒到5秒
                    //if (xfMotionCount >= 5 || (m_bankFaultTimeCount[k] >= (20 * 3) &&
                    //	m_bankFaultTimeCount[k] >= (20 * 5))) // 确认消防动作

                    //  if (xfMotionCount >= 5 ||
                    //  	(0xBBBB == m_oldBankState[k] &&
                    //  	m_bankFaultTimeCount[k] >= (20 * 3) &&
                    //	m_bankFaultTimeCount[k] >= (20 * 6)))
                    if (xfMotionCount >= 4 || 0xBBBB == m_oldBankState[k])
                    {
                        if (1 == KgGlobalData::ms_isGaoTeVer) // modified 2023-8-9
                        {
                            if (1 == pBank->usDI3)
                            //if (0 == pBank->usDry3State)
                            {
                                strContextEn = QString("fault starting，control #%1cluster open.").arg(k+1);
                                saveLogToBaDb(QString("发生故障，控制#%1簇脱扣.").arg(k+1), strContextEn);
                                pBank->usBankTemp[28] = 0;
                                pBank->usDry3Ctrl = 1;    // 干接点3控制  分励驱动断路器 DO3 // GaoTe
                                pBank->iDry3CtrlNum = 3;  // 干接点3控制次数
                            }
                        }
                        else
                        {
                            if (1 == pBank->usDI3)
                            //if (0 == pBank->usDry5State)
                            {
                                strContextEn = QString("fault starting，control #%1cluster open.").arg(k+1);
                                saveLogToBaDb(QString("发生故障，控制#%1簇脱扣.").arg(k+1), strContextEn);
                                pBank->usBankTemp[28] = 0;
                                pBank->usDry5Ctrl = 1;    // 干接点5控制  分励驱动断路器 DO5
                                pBank->iDry5CtrlNum = 3;  // 干接点5控制次数
                            }
                        }
                        m_oldBankState[k] = 0xAAAA;
                    }
                    else
                    {
                        //printf("1===pBank->usBankTemp[28]===============%d\n", pBank->usBankTemp[28]);
                        if (pBank->usBankTemp[28] < 100)// 400
                        {
                            pBank->usBankTemp[28] += 1;
                        }
                        else if (pBank->usBankTemp[28] < 200)
                        {
                            pBank->usBankTemp[28] += 1;
                            if (1 == KgGlobalData::ms_isGaoTeVer)
                            {
                                //if (1 == pBank->usDry3State)
                                //{
                                pBank->usDry3Ctrl = 0;       // 干接点3控制
                                pBank->iDry3CtrlNum = 3;     // 干接点3控制次数
                                //}
                            }
                            else
                            {
                                //if (1 == pBank->usDry5State)
                                //{
                                pBank->usDry5Ctrl = 0;       // 干接点5控制
                                pBank->iDry5CtrlNum = 3;     // 干接点5控制次数
                                //}
                            }
                        }
                        else
                        {
                            ;
                        }
                    }
                }
            }
            else
            {
                //printf("2====pBank->usBankTemp[28]===============%d\n", pBank->usBankTemp[28]);
                if (0xBBBB == pBank->usBankState || 0x1111== pBank->usBankState || 0x2222 == pBank->usBankState ||
                    0xCCCC == pBank->usBankState || 0x5555 == pBank->usBankState)
                {
                    m_oldBankState[k] = 0xBBBB;
                }

                pIOModule->usDOCtrl[1+k] = 0;// PCS故障干节点

                if (pBank->usBankTemp[28] < 100)// 400
                {
                    pBank->usBankTemp[28] += 1;
                }
                else if (pBank->usBankTemp[28] < 200)
                {
                    pBank->usBankTemp[28] += 1;
                    if (1 == KgGlobalData::ms_isGaoTeVer)
                    {
                        //if (1 == pBank->usDry3State)
                        //{
                        pBank->usDry3Ctrl = 0;       // 干接点3控制
                        pBank->iDry3CtrlNum = 3;     // 干接点3控制次数
                        //}
                    }
                    else
                    {
                        //if (1 == pBank->usDry5State)
                        //{
                        pBank->usDry5Ctrl = 0;       // 干接点5控制
                        pBank->iDry5CtrlNum = 3;     // 干接点5控制次数
                        //}
                    }
                }
                else
                {
                    ;
                }
            }
        }
    }

    if (hasSysError)
    {
        pIOModule->usDOCtrl[11] = 1;       // 故障指示灯硬接点 DO12
    }
    else
    {
        pIOModule->usDOCtrl[11] = 0;
    }
}

// 判断各簇QF1开关状态 
void DryCtrlThread::JudgeDIState()
{
    CIOModule *pIOModule = ::getIOModule();// KgGlobalData::ms_pRTDB->getIOModule();
    if (0 == m_hasReadIoState) // 还没有读取DI
    {
        m_hasReadIoState = 1;
        for (int i = 0; i < 10; ++i)
        {
            m_usOldDI[3+i] = pIOModule->usDI[3+i];
        }
    }
    else
    {
        for (int i = 0; i < 10; ++i)
        {
            quint16 newDI = pIOModule->usDI[3+i];
            if (m_usOldDI[3+i] != newDI)// 簇QF1开关状态发生变化
            {
                m_usOldDI[3+i] = newDI;
                QString strLog;
                QString strContextEn = "";
                if (newDI)
                {
                    strLog = QString("#%1簇QF1开关闭合.").arg(i+1);
                    strContextEn = QString("#%1Cluster QF1 switch close.").arg(i+1);
                }
                else
                {
                    strLog = QString("#%1簇QF1开关断开.").arg(i+1);
                    strContextEn = QString("#%1Cluster QF1 switch open.").arg(i+1);
                }
                saveLogToBaDb(strLog, strContextEn);
            }
        }
    }
}

void DryCtrlThread::SaveEmsFltkLog()
{
    /*
	for (int k = 0;  k < KgGlobalData::ms_installBankNum; ++k)
	{
	    //if (isBankInStack(k))
	    {
			CBattBank *pBank = KgGlobalData::ms_pRTDB->getBank(k);
			if (1000 == pBank->usBankTemp[28])// 有EMS分励驱动断路器，xnextio收到后进行日志记录
			{
				 pBank->usBankTemp[28] = 0;
				 QString strLog = QString("EMS控制%1#簇高压箱分励脱扣.").arg(k+1);
				 saveLogToBaDb(strLog);
			}
		}
	}
	*/
}

// 高特运行灯，故障处理 added 2023-7-28
// DO3-断路器 DO6-故障指示灯 DO7-运行指示灯
void DryCtrlThread::ctrlErrorLamp(CBattStack *pStack)
{
    for (int i = 0; i < KgGlobalData::ms_installBankNum; ++i)
    {
        CBattBank *pBank = KgGlobalData::ms_pRTDB->getBank(i);
        if (pBank)
        {
            if (0xAAAA == pBank->usBankState) // 故障
            {
                if (0 == pBank->usDry5State) // 点亮 DO6故障灯
                {
                    pBank->usDry5Ctrl = 1;
                    pBank->iDry5CtrlNum = 3;
                }
                if (1 == pBank->usDry6State)
                {
                    pBank->usDry6Ctrl = 0;
                    pBank->iDry6CtrlNum = 3;
                }
            }
            else  // 正常
            {
                if (1 == pBank->usDry5State)
                {
                    pBank->usDry5Ctrl = 0;
                    pBank->iDry5CtrlNum = 3;
                }
                if (0 == pBank->usDry6State)// 点亮 DO7运行灯
                {
                    pBank->usDry6Ctrl = 1;
                    pBank->iDry6CtrlNum = 3;
                }
            }
        }
    }
}

int printConfSwitchCount = 0;
void DryCtrlThread::dealWithConfSwitchStrategy(CBattStack *pStack)
{
    if (printConfSwitchCount < 50)
    {
        printConfSwitchCount += 1;
        QString strLog = QString("****************usConfSwitchStrategy:%1, diSize:%2 ")
                             .arg(pStack->usConfSwitchStrategy).arg(KgGlobalData::ms_hlkgStrategy.diCfgList.size());
        writeKgLogfile(strLog);
    }

    if (0 == KgGlobalData::ms_confSwitchEnabled)
    {
        if (3 == pStack->usConfSwitchStrategy)
        {
            pStack->usConfSwitchStrategy = 0;
            updateConfSwitchStrategy(0);
            QString strLog = "取消汇流开关策略, 重启生效.";
            saveLogToBaDb(strLog, "cancel confluence switch strategy, will valid after reboot.");
        }
        return;
    }

    if (2 == KgGlobalData::ms_confSwitchEnabled)// 强制显示 // added 2024-10-15
    {
        if (3 != pStack->usConfSwitchStrategy)
        {
            pStack->usConfSwitchStrategy = 3; // 汇流开关策略    1 - BC 2- BA 3 - ExtIO
            updateConfSwitchStrategy(3);
            QString strLog = "配置汇流开关策略, 重启生效.";
            saveLogToBaDb(strLog, "config confluence switch strategy, will valid after reboot.");
        }
        return;
    }

    // modified 2023-12-13
    if (KgGlobalData::ms_hlkgStrategy.diCfgList.size() > 0 &&
        KgGlobalData::ms_hlkgStrategy.hzDoList.size() > 0 &&
        KgGlobalData::ms_hlkgStrategy.fzDoList.size() > 0)
    {
        if (3 != pStack->usConfSwitchStrategy)
        {
            pStack->usConfSwitchStrategy = 3; // 汇流开关策略    1 - BC 2- BA 3 - ExtIO
            updateConfSwitchStrategy(3);
            QString strLog = "配置汇流开关策略, 重启生效.";
            saveLogToBaDb(strLog, "config confluence switch strategy, will valid after reboot.");
        }
    }
    else
    {
        if (3 == pStack->usConfSwitchStrategy)
        {
            pStack->usConfSwitchStrategy = 0;
            updateConfSwitchStrategy(0);
            QString strLog = "取消汇流开关策略, 重启生效.";
            saveLogToBaDb(strLog, "cancel confluence switch strategy, will valid after reboot.");
        }
    }

    this->msleep(500);

    if (printConfSwitchCount < 50)
    {
        printConfSwitchCount += 1;
        QString strLog = QString("****************usConfSwitchStrategy:%1, diSize:%2 ")
                             .arg(pStack->usConfSwitchStrategy).arg(KgGlobalData::ms_hlkgStrategy.diCfgList.size());
        writeKgLogfile(strLog);
    }
}

// 2022-3-30测试 616ms循环一次 DryCtrl/XfConfirmedCount配置为6时，从检测到消防信号，到报消防告警大约需3秒
// 2023-6-16
void DryCtrlThread::run()
{
    int ret = 0;
    quint16 runCount = 0;
    QString strHint;
    DryData &m_Para = KgGlobalData::ms_dryData;

    sleep(1);//程序刚启动时，本程序晚一点运行
    //m_pRtuClient = new CXnSerial;// Client

    if (KgGlobalData::ms_pStack != 0)
    {
        dealWithConfSwitchStrategy(KgGlobalData::ms_pStack);
    }

    /*for (int i = 0; i < KgGlobalData::ms_installBankNum; ++i)
	{
		CBatt Bank *pBank = KgGlobalData::ms_pRTDB->getBank(i);
		if (pBank)
		{
			for (int i = 0; i < 400; ++i)
			{
				pBank->fSglVol[i] = 3.12;
				pBank->fSglTemp[i] = 32;
			}
		}
	}*/

    //for (int k = 0; k < 5; ++k) // testing
    //{
    //	KgGlobalData::ms_pStack->usStackTemp[k] = 10 + k;
    //}

    /*
	CBattStack *pStack = KgGlobalData::ms_pRTDB->getStack(0);
	if (0 == pStack)
	{
	   printf("pStack is null\n");
	   return;
	}
	*/
    writeKgLogfile(QString("step500"));
    //saveLogToBaDb(kgConvert("IO程序开始运行."));
    int tickCount = 0;
    int judgeDiCount = 0;
    int softRunTime = 0;
    CIOModule *pIOModule = ::getIOModule();// KgGlobalData::ms_pRTDB->getIOModule();
    CBattStack *pStack = KgGlobalData::ms_pRTDB->getStack(0);
    m_pStack = pStack;
    CBattBank *pBank = KgGlobalData::ms_pRTDB->getBank(0);
    int xfAlarmCount = 0;
    int xfMotionCount = 0;
    int xfErrorCount = 0;
    int xfctrlDlqCount = 0; // 消防时控制总交流断路器断开次数

    int yljProtCount = 0;
    QChar c = '0';
    QString strState;

    /*
	writeKgLogfile(QString("======SglVol:%1--%2--%3  %4--%5--%6").arg(pBank->fSglVol[0]).arg(pBank->fSglVol[1]).arg(pBank->fSglVol[2])
		.arg(pBank->fSglVol[14]).arg(pBank->fSglVol[15]).arg(pBank->fSglVol[16]));
	writeKgLogfile(QString("======SglTemp:%1--%2--%3   %4--%5--%6").arg(pBank->fSglTemp[0]).arg(pBank->fSglTemp[1]).arg(pBank->fSglTemp[2])
		.arg(pBank->fSglTemp[14]).arg(pBank->fSglTemp[15]).arg(pBank->fSglTemp[16]));

	writeKgLogfile(QString("======SglTemp364:%1--%2--%3   %4--%5--%6").arg(pBank->fSglTemp[363]).arg(pBank->fSglTemp[364]).arg(pBank->fSglTemp[365])
		.arg(pBank->fSglTemp[381]).arg(pBank->fSglTemp[382]).arg(pBank->fSglTemp[383]));

	writeKgLogfile(QString("======usFaultLampCtrlDONo:%1, usRunLampCtrlDONo:%2")
		.arg(pStack->usFaultLampCtrlDONo).arg(pStack->usRunLampCtrlDONo));
	//pStack->usRunLampCtrlDONo = 3;
	//pStack->usFaultLampCtrlDONo = 4;
	*/
    writeKgLogfile(QString("======usRunLampCtrlDONo:%1, usFaultLampCtrlDONo:%2").arg(pStack->usRunLampCtrlDONo).arg(pStack->usFaultLampCtrlDONo));
    printf("usPackPowerLineStrategy:%d, usBankPowerLineStrategy:%d\n", 
           pStack->usPackPowerLineStrategy,pStack->usBankPowerLineStrategy);

    for (int i = 0; i < KgGlobalData::ms_installBankNum; ++i)
    {
        CBattBank *pBank = KgGlobalData::ms_pRTDB->getBank(i);
        if (pBank)
        {
            /*int pos = 240;
			QString strTemp = QString("Bank%1 temp241--256:%2,%3,%4,%5,%6,  %7,%8,%9,%10,%11,  %12,%13,%14,%15,%16,%17").arg(i+1)
				.arg(pBank->fSglTemp[pos++]).arg(pBank->fSglTemp[pos++]).arg(pBank->fSglTemp[pos++]).arg(pBank->fSglTemp[pos++]).arg(pBank->fSglTemp[pos++])
				.arg(pBank->fSglTemp[pos++]).arg(pBank->fSglTemp[pos++]).arg(pBank->fSglTemp[pos++]).arg(pBank->fSglTemp[pos++]).arg(pBank->fSglTemp[pos++])
				.arg(pBank->fSglTemp[pos++]).arg(pBank->fSglTemp[pos++]).arg(pBank->fSglTemp[pos++]).arg(pBank->fSglTemp[pos++]).arg(pBank->fSglTemp[pos++])
                .arg(pBank->fSglTemp[pos++]);
			writeKgLogfile(strTemp);*/
            int pos = 0;
            QString strTemp = QString("Bank%1 temp1--10:%2,%3,%4,%5,%6,  %7,%8,%9,%10,%11").arg(i+1)
                                  .arg(pBank->fSglTemp[pos++]).arg(pBank->fSglTemp[pos++]).arg(pBank->fSglTemp[pos++]).arg(pBank->fSglTemp[pos++]).arg(pBank->fSglTemp[pos++])
                                  .arg(pBank->fSglTemp[pos++]).arg(pBank->fSglTemp[pos++]).arg(pBank->fSglTemp[pos++]).arg(pBank->fSglTemp[pos++]).arg(pBank->fSglTemp[pos++]);
            writeKgLogfile(strTemp);

            printf("****Bank%d DO1-DO8 state:%d(Wet)-%d-%d-%d(DO4)-%d(DO5)-%d(DO6)-%d(DO7)-%d(DO8)\n",
                   i+1, pBank->usWetState, pBank->usDry1State, pBank->usDry2State, pBank->usDry3State,
                   pBank->usDry4State,pBank->usDry5State,pBank->usDry6State,pBank->usDry7State);
            continue;

            writeKgLogfile(QString("=====Bank%1 BankVol:%2, BankCur:%3.").arg(i+1).arg(pBank->fBankVol).arg(pBank->fBankCur));
            QChar fillChar = '0';
            QString strState = QString("0X%1").arg(pBank->usBankState,4,16,fillChar).toUpper();
            strHint = QString("=====Bank%1 runStateDO3:%2, errStateDO4:%3,DO5State:%4, usDI1to3:%5-%6-%7,bankState:%8")
                          .arg(i+1).arg(pBank->usDry3State).arg(pBank->usDry4State).arg(pBank->usDry5State)
                          .arg(pBank->usDI1).arg(pBank->usDI2).arg(pBank->usDI3).arg(strState);

        }
    }

    // added 2023-7-28
    if (1 == KgGlobalData::ms_isGaoTeVer)
    {
        pStack->usFaultLampCtrlDONo = 0; // 故障灯控制  1 ~ 5, DO1 ~ DO5
        pStack->usRunLampCtrlDONo = 0;   // 运行灯控制  1 ~ 5, DO1 ~ DO5
    }

    printf("1=====aEnvTemp[0]to[5]:%d-%d-%d-%d-%d-%d\n", pStack->aEnvTemp[0],pStack->aEnvTemp[1],
           pStack->aEnvTemp[2],pStack->aEnvTemp[3],pStack->aEnvTemp[4],pStack->aEnvTemp[5]);


    printf("1=====aWaterAlarm:%d, aEnvWaterAlarm[0]:%d,bank aWaterAlarm:%d\n",
           pStack->aWaterAlarm,pStack->aEnvWaterAlarm[0],0);// pBank->aWaterAlarm

    sleep(2);

    //KgGlobalData::ms_pStack->aEnvTemp[0] = 5;
    //pStack->aFireWarn = 0;

    //if (KgGlobalData::ms_hlkgStrategy.diCfgList.size() > 0)
    //	pStack->usConfSwitchStrategy = 3;// 汇流开关策略    1 - BC 2- BA 3 - ExtIO
    if (KgGlobalData::ms_emgStopStrategy.diList.size() > 0)
        pStack->usEmerStopStrategy    = 3;// 紧急停机策略     1 - BC 2- BA 3 - ExtIO
    if (KgGlobalData::ms_xfStrategy.diList.size() > 0)
        pStack->usFireWarnStrategy   = 3; // 消防预警策略     1 - BC 2- BA 3 - ExtIO
    if (KgGlobalData::ms_xfSprayStrategy.diList.size() > 0)
        pStack->usFireActionStrategy = 3; // 消防启动策略     1 - BC 2- BA 3 - ExtIO
    if (KgGlobalData::ms_xfFaultStrategy.diList.size() > 0)
        pStack->usFireFaultStrategy = 3; // 消防故障策略     1 - BC 2- BA 3 - ExtIO
    if (KgGlobalData::ms_waterStrategy.diList.size() > 0)
        pStack->usWaterStrategy = 3;     // 水浸告警策略     1 - BC 2- BA 3 - ExtIO
    if (KgGlobalData::ms_combusGasStrategy.diList.size() > 0)
        pStack->usGasStrategy = 3;// 可燃气体策略     1 - BC 2- BA 3 - ExtIO
    if (KgGlobalData::ms_doorAlmStrategy.diList.size() > 0)
        pStack->usAcceCtrlStrategy = 3;// 门禁状态策略     1 - BC 2- BA 3 - ExtIO

    while(1)
    {
        msleep(100);

        if (runCount < 5)
        {
            CIOModule *m_pIOModule = KgGlobalData::ms_pIOModule;
            printf("DryCtrlThread read usDOCtrl1-12:%d-%d-%d-%d-%d-%d, %d-%d-%d-%d-%d-%d\n",
                   m_pIOModule->usDOCtrl[0],m_pIOModule->usDOCtrl[1],m_pIOModule->usDOCtrl[2],m_pIOModule->usDOCtrl[3],
                   m_pIOModule->usDOCtrl[4],m_pIOModule->usDOCtrl[5],m_pIOModule->usDOCtrl[6],m_pIOModule->usDOCtrl[7],
                   m_pIOModule->usDOCtrl[8],m_pIOModule->usDOCtrl[9],m_pIOModule->usDOCtrl[10],m_pIOModule->usDOCtrl[11]);
        }
        //printf("2=====aEnvTemp[0]:%d\n", KgGlobalData::ms_pStack->aEnvTemp[0]);
        //msleep(1000);
        //continue;

        if (softRunTime < 30000)
        {
            softRunTime += 1;
        }

        //if (++tickCount >= 60) // 每3秒输出一次
        {
            tickCount = 0;
            printDiDoState();
            int closeDqlCount = GetCloseDlqCount();
            writeKgLogfile(QString("closeDqlCount:%1").arg(closeDqlCount));
        }

        /* NWYL programe

		if (++runCount >= 30000)
		{
			runCount = 20;
		}
		// 消防控制策略, 断开总交流断路器和10个直流断路器
		JudgeXfMotion(xfAlarmCount, xfMotionCount, xfErrorCount, xfctrlDlqCount, runCount);
		JudgeYljError(yljProtCount, xfctrlDlqCount, runCount);// added 2023-10-25
		
		if (1 == KgGlobalData::ms_isGaoTeVer)
		{
			ctrlErrorLamp(pStack); // GaoTe
		}

		int tmpCtrlVal = xfMotionCount;
		if (yljProtCount > tmpCtrlVal)
		{
			tmpCtrlVal = yljProtCount;
		}
		//TellPcsError(xfMotionCount, runCount, 1);
		TellPcsError(tmpCtrlVal, runCount, 1); // modified 2023-10-25

		if (softRunTime >= 200) // 程序启动后过10秒再判断
		{
			if (++judgeDiCount > 20) // 每过1秒判断一次
			{
				judgeDiCount = 0;
				JudgeDIState();

				SaveEmsFltkLog();
			}
		}
		
		continue;
		*/
        /////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////
#ifdef VER20_EMS
        CXfData *pXfData = KgGlobalData::ms_pRTDB->getXfDev(0);
#endif		
        if (runCount < 100)
        {
            runCount += 1;

            writeKgLogfile(QString("step101 aEmerStop:%1,aFireWarn:%2,aFireAction:%3,aFireFault:%4.")
                               .arg((int)pStack->aEmerStop).arg((int)pStack->aFireWarn).arg((int)pStack->aFireAction)
                               .arg((int)pStack->aFireFault));

#ifdef VER20_EMS
            writeKgLogfile(QString("aEnvWaterAlarm:%1, xfData connError:%2, usDevTemp[0]:%3(state), usDevTemp[1]:%4(level), usDevTemp[2]:%5.")
                               .arg((int)pStack->aEnvWaterAlarm[0]).arg((int)pXfData->connError).arg((int)pXfData->usDevTemp[0]).arg((int)pXfData->usDevTemp[1]).arg((int)pXfData->usDevTemp[2]));
#endif		
            strState = QString("%1").arg(pBank->usBankState,4,16,c).toUpper();
            writeKgLogfile(QString("BankState:0X%1,usChgState:%2,DIState:%3-%4-%5-%6-%7-%8.")
                               .arg(strState).arg((int)pBank->usBankChgDchgState).arg(pBank->usDI1)
                               .arg(pBank->usDI2).arg(pBank->usDI3).arg(pBank->usDI4).arg(pBank->usDI5).arg(pBank->usDI6));

            writeKgLogfile(QString("aAcceCtrlState:%1-%2,aWaterAlarm:%3,aEnvWaterAlarm[0][1]:%4,%5.")
                               .arg((int)pStack->aAcceCtrlState).arg((int)pStack->aEnvTemp[10])
                               .arg((int)pStack->aWaterAlarm).arg((int)pStack->aEnvWaterAlarm[0]).arg((int)pStack->aEnvWaterAlarm[1]));

            writeKgLogfile(QString("485Water:%1-%2(aEnvTemp[30]-[31]), 485xfAlarm:%3-%4(aEnvTemp[32]-[33]), xfMotion:%5,%6(aEnvTemp[34]-[35]), xfFault:%7-%8(aEnvTemp[36]-[37]) runCount:%9.")
                               .arg((int)pStack->aEnvTemp[30]).arg((int)pStack->aEnvTemp[31])
                               .arg((int)pStack->aEnvTemp[32]).arg((int)pStack->aEnvTemp[33])
                               .arg((int)pStack->aEnvTemp[34]).arg((int)pStack->aEnvTemp[35])
                               .arg((int)pStack->aEnvTemp[36]).arg((int)pStack->aEnvTemp[37])
                               .arg(runCount));

            writeKgLogfile(QString("m_bmsLocalState:%1, m_bmsRemoteState:%2.")
                               .arg((int)m_bmsLocalState).arg((int)m_bmsRemoteState));
        }
        else if (runCount < 30000)
        {
            runCount += 1;
            writeKgLogfile(QString("step101 aEmerStop:%1,aFireWarn:%2,aFireAction:%3,aFireFault:%4.")
                               .arg((int)pStack->aEmerStop).arg((int)pStack->aFireWarn).arg((int)pStack->aFireAction)
                               .arg((int)pStack->aFireFault));
#ifdef VER20_EMS
            writeKgLogfile(QString("aEnvWaterAlarm:%1, xfData connError:%2, usDevTemp[0]:%3(state), usDevTemp[1]:%4(level), usDevTemp[2]:%5.")
                               .arg((int)pStack->aEnvWaterAlarm[0]).arg((int)pXfData->connError).arg((int)pXfData->usDevTemp[0]).arg((int)pXfData->usDevTemp[1]).arg((int)pXfData->usDevTemp[2]));
#endif			
            writeKgLogfile(QString("485Water:%1-%2(aEnvTemp[30]-[31]), 485xfAlarm:%3-%4(aEnvTemp[32]-[33]), xfMotion:%5,%6(aEnvTemp[34]-[35]), xfFault:%7-%8(aEnvTemp[36]-[37]) runCount:%9.")
                               .arg((int)pStack->aEnvTemp[30]).arg((int)pStack->aEnvTemp[31])
                               .arg((int)pStack->aEnvTemp[32]).arg((int)pStack->aEnvTemp[33])
                               .arg((int)pStack->aEnvTemp[34]).arg((int)pStack->aEnvTemp[35])
                               .arg((int)pStack->aEnvTemp[36]).arg((int)pStack->aEnvTemp[37])
                               .arg(runCount));
        }
        else
            ;
        //KgGlobalData::ms_pStack->aEnvWaterAlarm[0] = m_waterAlarm;

        /*if (++tickCount >= 10) // 如果用户配置DIDO有变化，则重新加载 // added 2023-01-05
		{
			bool ret = reloadDIDOConfig();
			if (ret) // reload succeed
			{
				writeKgLogfile(QString("reload succeed, sleep 500 msec ..."));
				this->msleep(500);
			}
			tickCount = 0;
		}*/

        getInstallInfo();

        CBattStack *pStack = KgGlobalData::ms_pRTDB->getStack(0);
        if (pStack)
        {
            //pStack->fStackVol = 632;
            //pStack->fStackCur = -12.3;
            //pStack->usDI3 = 1;
            //pStack->usDI4 = 1;
            //msleep(2000);
            //continue; // testing
        }

        /*  testing for YW-PF0318
		KgGlobalData::ms_pStack->aExIOModuConnFault = 0;  // added 2022-5-22
		SetEmergeStopAlarm(0); //
		writeKgLogfile(QString("==================Moni emergency over."));
		this->msleep(2000);
		continue;
		*/

        if (0 == KgGlobalData::ms_pStack)
        {
            printf("pStack is null.\n");
            this->msleep(2000);
            continue;
        }

        if (999 == KgGlobalData::ms_zz404D_addr)
        {
            KgGlobalData::ms_pStack->aExIOModuConnFault = 0;
            if (KgGlobalData::ms_hlkgStrategy.diCfgList.size() > 0)
            {
                KgGlobalData::ms_pStack->usConfSwitchState = 2;//通知BA 汇流开关已经断开
                KgGlobalData::ms_pStack->aConfSwitchState = 0;
            }
            //writeKgLogfile(QString("Do not have IO module"));
            msleep(200);
            continue;
        }
        else if (1000 == KgGlobalData::ms_zz404D_addr)
        {
            KgGlobalData::ms_pStack->aExIOModuConnFault = 1;
            if (KgGlobalData::ms_hlkgStrategy.diCfgList.size() > 0)
            {
                KgGlobalData::ms_pStack->usConfSwitchState = 2;//通知BA 汇流开关已经断开
                KgGlobalData::ms_pStack->aConfSwitchState = 0;
            }
            msleep(200);
            continue;
        }
        else
            ;

        /*
        // writeKgLogfile(QString("step501"));
        // added 2023-2-3
		DryDIDOConfig &oldSet = KgGlobalData::ms_oldDiDoSet;
	    if (0 == oldSet.usExIOCommSerialPortNo) // 没有IO设备
	    {
	    	KgGlobalData::ms_pStack->aExIOModuConnFault = 0;
			writeKgLogfile(QString("==================ExIOCommSerialPortNo is 0, No IO Dev."));
	    	this->msleep(2000);
			continue;
	    }
		// added end

		if (!m_pIOReader->openSerialPort())
		{
			this->msleep(5000);
			continue;
		}
*/	
        // 第1帧：读取DO状态=========================================================1 Read DO
        //readDevDOState();
        m_pIOReader->readDevDOState(0, KgGlobalData::ms_dryData);
        // writeKgLogfile(QString("step502"));

        // 第2帧：根据工况设置DO (如果状态没有改变，则不下发)========================2 Set DO
        setSomeDOState();

        if (runCount >= 5) // 3 // modifed 2023-12-14
        {
            if (KgGlobalData::ms_execFltkFirst)
            {
                controlOtherFz();// 控制其他脱扣

                if (KgGlobalData::ms_hlkgStrategy.xfTkDoList.size() > 0 && m_xfTkMotionCount > 0 &&  m_xfTkMotionCount < KgGlobalData::ms_ctrlConfSwitchCount)
                {
                    // Doing TuoKou1 3 times first
                }
                else if (KgGlobalData::ms_hlkgStrategy.xfSprayTkDoList.size() > 0 && m_xfSprayTkMotionCount > 0 &&  m_xfSprayTkMotionCount < KgGlobalData::ms_ctrlConfSwitchCount)
                {
                    // Doing TuoKou2 3 times first
                }
                else if (KgGlobalData::ms_hlkgStrategy.volDownProtFzDoList.size() > 0 && m_volDownProtTkCount > 0 &&  m_volDownProtTkCount < KgGlobalData::ms_ctrlConfSwitchCount)
                {
                    // Doing TuoKou2 3 times first
                }
                else
                {
                    controlHzFz();   // 控制汇流开关，此处有延时，所以要单独分开执行
                }
            }
            else
            {
                controlHzFz();   // 控制汇流开关，此处有延时，所以要单独分开执行
                controlOtherFz();// 控制其他脱扣
            }
        }

        // writeKgLogfile(QString("step503"));
        // 第3帧：读取DI状态并判断消防告警===========================================3 Read DI
        msleep(50);
        readDIValue(runCount);

        // 检测DI状态变化并更新到ini文件
        updateDIValuesToIniFile(KgGlobalData::ms_pStack);


#ifdef HAS_SECOND_IO_DEV
        // 读取第二个IO模块的DI数据 // added 2022-8-2
        int oldDIVal = KgGlobalData::ms_drySecData.DIVal;
        m_pIOReader->readDevDIState(1, KgGlobalData::ms_drySecData);//查询成功
        if (oldDIVal != KgGlobalData::ms_drySecData.DIVal)
        {
            this->msleep(500);
            m_pIOReader->readDevDIState(1, KgGlobalData::ms_drySecData);//查询成功
        }
#endif	
        if (runCount >= 1)
        {
            // deleted 2023-11-9
            updateDryDataToRtdb(this);    //更新DI1-4数据到BA的通用保持寄存器50-53中 2020-1-15
        }
    }
}
